ChatGPT解决这个技术问题 Extra ChatGPT

C# 中 Task.FromResult<TResult> 的用途是什么

在 C# 和 TPL (Task Parallel Library) 中,Task 类表示正在进行的工作,该工作产生 T 类型的值。

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

那就是:在你手头已经有了产生的价值的情况下,有什么必要将它包装回任务中?

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

在某种程度上我同意这一点,但是像这样创建密集的、有用的、统一的、面向讨论的页面是一个巨大的好处。我几乎总是从一个好的、密集的 stackoverflow 页面中学到更多,而不是从谷歌搜索和跨多个地方进行研究,所以在这种情况下,我真的很高兴他发布了这个。
我认为谷歌把我带到了 SO 和 SO 让我去谷歌。这是一个循环引用:)

S
Stephen Cleary

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

当您实现一个允许异步调用者的接口时,但您的实现是同步的。当您为测试而存根/模拟异步代码时。


#1 的一个好案例是 Web 服务。您可以有一个返回 Task.FromResult 的同步服务方法和一个异步等待网络 I/O 的客户端。这样,您可以使用 ChannelFactory 在客户端/服务器之间共享相同的接口。
例如 ChallengeAsync 方法。 WTF 是 MS 的设计师在想什么?此方法绝对没有理由返回任务。 MS 的所有示例代码都只有 FromResult(0)。希望编译器足够聪明,可以优化它,并且实际上不会产生一个新线程然后立即杀死它!
@JohnHenckel:OWIN 从一开始就设计为异步友好的。接口和基类经常使用异步签名,因为它只是允许(而不是强制)实现是异步的。因此,它类似于从 IDisposable 派生的 IEnumerable<T> - 它允许可枚举拥有一次性资源,而不是强制它。 FromResultasyncawait 都不会产生线程。
@StephenCleary 嗯,感谢您解释。我曾认为 await 会产生,但我试过了,我发现它没有。只有 Task.Run 可以。因此,x = await Task.FromResult(0);相当于说 x = 0;这很令人困惑,但很高兴知道!
@OlegI:对于 I/O 操作,最好的 解决方案是异步实现它,但有时您没有选择。此外,有时您可以同步实现它(例如,缓存结果,如果值未缓存,则回退到异步实现)。更一般地说,返回 Task 的方法意味着“可能是异步的”。所以有时方法被赋予一个异步签名,完全知道某些实现将是同步的(例如,NetworkStream 应该是异步的,但 MemoryStream 应该是同步的)。
H
Himanshu

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

缓存示例:Cache Example using Task.FromResult for Pre-computed values


并且可以缓存已完成的任务,例如从 Task.FromResult 返回的任务。
@Paulo:将整个 Task 对象保存在内存中似乎比只缓存结果更浪费。
期望“价值任务”已经被缓存。我不记得具体是哪些,但我认为 Task.FromResult(0)Task.FromResult(1)Task.FromResult(false)Task.FromResult(true) 被缓存了。您不应该为网络访问缓存任务,但结果中的一个任务非常好。您是否愿意在每次需要返回值时创建一个?
...并回答我自己的问题,任务缓存的好处是其中一些可以完成任务,而另一些可以是尚未完成的任务。调用者不必关心:他们进行异步调用,如果已经完成,则在等待时立即得到答案,如果没有,则稍后再获得。如果没有这些缓存任务,要么 (a) 需要两种不同的机制,一种是同步的,一种是异步的——这对调用者来说很麻烦,或者 (b) 必须动态创建一个任务,每次调用者要求一个已经可用的答案时(如果我们只缓存了一个 TResult)。
我现在明白了。答案的措辞有些混乱。任务本身没有内置的“缓存”机制。但是,如果您为 ... 说 .... 下载文件编写了一个缓存机制,Task GetFileAync( ),您可以使用 Task.FromResult(cachedFile) 立即返回一个已经在缓存中的文件,然后等待将同步运行,通过没有线程切换来节省时间。
E
Edminsson

当你想创建一个可等待的方法而不使用 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);
    }
}

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


g
goughy000

来自 MSDN:

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

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


A
Alborz

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


在您的好示例中,结果不是同步的,操作都是异步的,Task.FromResult 用于获取先前缓存的异步结果。
V
Viking

我认为您可以将 Task.FromResult 用于需要很长时间才能完成的同步方法,而您可以在代码中执行其他独立工作。我宁愿让这些方法调用异步。但是想象一下您无法控制调用的代码并且您想要隐式并行处理的情况。


不知道为什么 SO 排序将这个答案放在列表的顶部,但它是不正确的。调用 await Task.FromResult(...) 不会进行隐式并行处理(有关说明,请参见 this question)。而是同步运行。如果您希望转换一个长时间运行的同步方法以便它可以与另一个并行调用,您应该改用 await Task.Run(() => LongRunningTask());