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

时间:2018-06-06 18:05:41

标签: c# asynchronous async-await task

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

我有一个这样做的课程:

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

var innerValue = await Task.FromResult(value.Result);

Somefunction如下所示。

protected async Task<JObject> Somefunction(..)
{
 ..
 returns JBoject
 ..
}

这可以正常工作。现在,我建议不要将Task.FromResultasync函数一起使用。 相反,我应该使用类似的东西:

var innerValue = await value; //..this works fine too

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

2 个答案:

答案 0 :(得分:22)

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

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

首先:当类型清晰或不重要时使用var这里的类型不明确,很重要

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

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

Task<Toast> toastTask = this.StartToasterAsync();
Toast toast = await Task.FromResult(toastTask.Result);

此工作流程完全错误。让我们将其翻译成英文。这是我今天的待办事项清单:

  • 在烤面包机里放一些面包。
  • 当面包烘烤时,我可以做其他工作,但是,盯着烤面包机做其他事情,直到完成
  • 从烤面包机拿出烤面包,然后开始新的待办事项清单。
  • 新的待办事项清单是:获取我现在持有的吐司。
  • 执行该待办事项列表。当我等待待办事项列表完成时,继续做其他工作,但是待办事项列表总是已经完成,因为工作是获取我已经获得的结果。所以不要做其他工作。只要检查一下是的,我实际上拿着那片吐司,我刚刚写了一份待办事项清单。
  • 现在我有一片吐司。

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

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

永远不要永远不要这样写异步代码。

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

  • 将面包放入烤面包机并开始烘烤。
  • 做其他工作,直到吐司出现。
  • 拿取吐司。

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

Task<Toast> toastTask = this.StartToasterAsync(...);
Toast toast = await toastTask;

甚至更好:

Toast toast = await this.StartToasterAsync(...);

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

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

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

最后

  • FromResult表示某人需要一项任务,但我已经拥有该任务的结果,因此请创建一个已完成的任务。当它await或在其上调用Result时,无论哪种方式,都会立即返回结果。

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

答案 1 :(得分:3)

第一个版本中的问题不是使用Task.FromResult,而是来自文档:

  

创建使用指定结果

成功完成的Task<TResult>

问题是执行同步等待的调用value.Result。因此,您基本上是异步等待同步结果。

请注意,第一个版本是一个糟糕的包装器(因为必须为await调用生成代码):

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

总结一下,就这样使用:

var innerValue = await value;

或者,如果在valueinnerValue之间没有代码可以运行,则可以完全忽略value的分配

var innerValue = await this.SomeFunction(...);