在C#中使用Task.FromResult v/s等待

lea*_*arn 2 c# asynchronous task async-await

我是C#异步编程的新手,需要查看以下哪个是处理Task对象的首选方法.

我有一个类这样做:

var value = this.SomeFunction(...);

var innerValue = await Task.FromResult(value.Result);
Run Code Online (Sandbox Code Playgroud)

Somefunction 看起来如下.

protected async Task<JObject> Somefunction(..)
{
 ..
 returns JBoject
 ..
}
Run Code Online (Sandbox Code Playgroud)

这可以正常工作.现在,我有我不应该使用的建议Task.FromResultasync功能.相反,我应该使用类似的东西:

var innerValue = await value; //..this works fine too
Run Code Online (Sandbox Code Playgroud)

但我不确定为什么第一个不是一个很好的做法来完成同样的事情.任何线索都会有所帮助.谢谢

Eri*_*ert 25

让我们来看看你正在做的事情并准确地说出它为什么是错的.

var value = this.SomeFunction(...);
Run Code Online (Sandbox Code Playgroud)

首先:var当类型清晰或不重要时使用. 这种类型在这里并不清楚,这很重要.

第二:与Async后缀异步的名称函数.

让我们来解决你的例子吧.它仍然是错的,但现在更清楚了:

Task<Toast> toastTask = this.StartToasterAsync();
Toast toast = await Task.FromResult(toastTask.Result);
Run Code Online (Sandbox Code Playgroud)

这个工作流程完全错误. 我们把它翻译成英文.这是我今天的待办事项列表:

  • 把面包放在烤面包机里.
  • 虽然面包是敬酒的,但我可以做其他的工作,但相反,盯着烤面包机什么都不做,直到它完成.
  • 从烤面包机烤面包,并开始一个新的待办事项列表.
  • 新的待办事项列表是:获取我现在持有的吐司.
  • 执行该待办事项列表.当我等待待办事项列表完成时,继续做其他工作,但待办事项列表总是已经完成,因为工作是获取我已经获得的结果.所以不要做其他工作.只是检查是的,我实际上拿着这片吐司我刚写了一份待办事项列表.
  • 现在我有一片吐司.

这个工作流程是制作吐司的疯狂方式.它的工作原理 - 你最后得到了一片吐司 - 但没有明智的人会这样做,你不应该写相同的计算机程序:

  • 这是一个"异步"工作流程,其中删除了所有可能的异步优势.
  • 第一步 - 等待烤面包机弹出 - 已经同步等待.
  • 第二步 - 异步等待已经完成的任务 - 永远不会异步!

绝不永远不会以这种方式编写异步代码.

制作一片吐司的正确工作流程是:

  • 将面包放入烤面包机并开始烘烤.
  • 做吐司之前做其他工作.
  • 拿吐司.

正如我们所期望的,编写程序的正确方法要简单得多:

Task<Toast> toastTask = this.StartToasterAsync(...);
Toast toast = await toastTask;
Run Code Online (Sandbox Code Playgroud)

甚至更好:

Toast toast = await this.StartToasterAsync(...);
Run Code Online (Sandbox Code Playgroud)

您是新手,并没有内化异步工作流上各种操作的含义.您的小程序中的操作是:

  • .Result意味着停止异步,并在结果可用之前不执行任何操作.请注意,这可能会导致死锁.您正在停止一个线程,直到结果可用; 如果你要停止将来会产生结果的线程怎么办?想象一下,例如我们做了一个待办事项清单"(1)从互联网上订购一盒巧克力.(2)在巧克力到货之前什么也不做.(3)从巧克力中取出巧克力." 该工作流程未完成,因为同步等待结果需要您将来继续工作.
  • await表示此工作流无法继续,直到结果可用,因此异步等待它.下去找其他工作要做,当结果可用时,我们将在这里重新开始.

请注意,它们都意味着相同的事情,因为两者都是工作流中的点,在结果可用之前工作流不会继续.但他们是完全不同的Result同步的等待,并且await是一个异步等待. 确保你明白这一点.这是您必须了解的最基本点.

最后

  • FromResult意味着某人需要一项任务,但我已经拥有该任务的结果,因此请完成一项已经完成的任务.当它被await编辑或何时Result被调用时,无论哪种方式,它都会立即返回结果.

打电话是不寻常的FromResult.如果您处于异步工作流程中,通常只是return result;表示任务已完成.

  • 几乎我唯一一次使用“FromResult”是当我有一个带有虚拟异步方法的层次结构时,其中一个实现实际上不需要执行任何异步工作,因此我更喜欢返回已完成的任务而不是有一个“没有“await”的 async` 标记方法。 (6认同)