在C#中Task.FromResult <TResult>有什么用?

lys*_*cid 170 .net c# task task-parallel-library async-await

在C#和TPL(任务并行库)中,Task该类表示正在进行的工作,它产生类型为T的值.

我想知道Task.FromResult方法有什么需要?

那就是:在您已经拥有生产价值的情况下,需要将其包装回任务中?

我唯一想到的是它被用作接受Task实例的其他方法的一些适配器.

Ste*_*ary 235

我发现了两个常见的用例:

  1. 当您实现允许异步调用者的接口时,但您的实现是同步的.
  2. 当您对用于测试的异步代码进行存根/模拟时.

  • @JohnHenckel:OWIN从头开始设计为异步友好型.接口和基类通常使用异步签名,因为它只允许*(而不是*force*)实现异步.所以它类似于`IEnumerable <T>`派生自`IDisposable` - 它*允许*可枚举具有可支配资源,而不是*强制*它.`FromResult`,`async`和`await`都不会产生线程. (11认同)
  • #1的一个好例子是Web服务.您可以使用同步服务方法返回`Task.FromResult`和一个异步等待网络I/O的客户端.这样,您可以使用`ChannelFactory`在客户端/服务器之间共享相同的接口. (5认同)
  • @OlegI:对于I/O操作,*best*解决方案是异步实现它,但有时你没有那个选择.此外,有时你*可以*同步实现它(例如,缓存的结果,如果没有缓存值,则回退到异步实现).更一般地,"任务"返回方法意味着"*可以*是异步的".所以有时候方法会得到一个异步签名,知道一些实现是同步的(例如,`NetworkStream`应该是异步的,但`MemoryStream`应该是同步的). (4认同)
  • @StephenCleary hmhm,谢谢你的解释.我曾经假设await会产生,但我尝试了它,我发现它没有.只有Task.Run才有.因此,x = await Task.FromResult(0); 相当于说x = 0; 那令人困惑,但很高兴知道! (3认同)
  • 例如ChallengeAsync方法.WTF是MS思维的设计师吗?这种方法绝对没有理由返回任务.来自MS的所有示例代码都只有FromResult(0).希望编译器足够智能以优化它,并且实际上不会产生新线程然后立即杀死它! (2认同)
  • @JohnHenckel我认为等待的第一件事是检查IsCompleted的状态,如果为true,则它同步地继续向下运行同一线程。Task.FromResult()创建一个任务,该任务已将IsCompleted设置为true以用于优化。 (2认同)
  • @StephenCleary 明白了。此外,我认为,当您创建抽象时,您希望它是可等待的,即使该抽象的具体实现还没有运行任何异步操作,但可能当您更改具体抽象实现时,它会调用可等待的东西。因此,使用 Task 作为返回类型声明抽象将使您的具体实现足够灵活,可以在不更改抽象签名的情况下运行同步和异步操作。如果我是对的,我觉得这是 Task.FromResult 的主要目的之一...... (2认同)
  • @OlegI:是的。这是“Task.FromResult”的一个用例;另一个用于单元测试(异步接口的存根实现)。 (2认同)

Mat*_*ith 48

一个示例是使用高速缓存的方法.如果已经计算了结果,则可以使用值(使用Task.FromResult)返回已完成的任务.如果不是,那么您继续并返回代表正在进行的工作的任务.

缓存示例:使用Task.FromResult为预先计算的值缓存示例

  • ...并回答我自己的问题,*Tasks*缓存的好处是,其中一些可以完成任务,而其他可以是尚未完成的任务.呼叫者不必关心:他们进行异步呼叫,如果已经完成,他们等待时会立即得到答案,如果没有,他们会在以后得到答案.如果没有这些缓存的任务,(a)需要两个不同的机制,一个同步和一个异步 - 对于调用者来说很麻烦,或者(b)每次调用者要求已经可用的答案时都必须动态创建一个任务(如果我们只缓存了一个TResult). (4认同)
  • 我现在明白了。答案的措辞有点令人困惑。任务本身没有内置的“缓存”机制。但是,如果您为...编写...下载文件的缓存机制,Task&lt;File&gt; GetFileAync(),您可以使用Task.FromResult(cachedFile)立即返回已经在缓存中的文件,并等待将同步运行,无需线程切换,从而节省时间。 (3认同)
  • @Paulo:将整个任务对象保留在内存中似乎比仅缓存结果要浪费得多。 (2认同)
  • 预期“价值任务”已被缓存。我不记得到底是哪些,但我认为 `Task.FromResult(0)`、`Task.FromResult(1)`、`Task.FromResult(false)` 和 `Task.FromResult(true)` 被缓存了。您不应该为网络访问缓存任务,但结果中的任务完全没问题。您是否愿意在每次需要返回值时创建一个? (2认同)

Edm*_*son 28

如果要在不使用async关键字的情况下创建等待方法,请使用它.我找到了这个例子:

public class TextResult : IHttpActionResult
{
    string _value;
    HttpRequestMessage _request;

    public TextResult(string value, HttpRequestMessage request)
    {
        _value = value;
        _request = request;
    }
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage()
        {
            Content = new StringContent(_value),
            RequestMessage = _request
        };
        return Task.FromResult(response);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,您将创建自己的IHttpActionResult接口实现,以在Web Api Action中使用.ExecuteAsync方法应该是异步的,但您不必使用async关键字使其异步和等待.由于您已经拥有结果并且不需要等待任何事情,因此最好使用Task.FromResult.


小智 19

来自MSDN:

当您执行返回Task对象的异步操作并且已经计算了该Task对象的结果时,此方法很有用.

http://msdn.microsoft.com/en-us/library/hh228607.aspx


Alb*_*orz 6

当您想要异步操作但有时结果是同步的时,请使用 Task.FromResult。您可以在这里找到一个很好的示例http://msdn.microsoft.com/en-us/library/hh228607.aspx