我是C#异步编程的新手,需要查看以下哪项是处理Task对象的首选方法。
我有一个这样做的课程:
var value = this.SomeFunction(...);
var innerValue = await Task.FromResult(value.Result);
Somefunction
如下所示。
protected async Task<JObject> Somefunction(..)
{
..
returns JBoject
..
}
这可以正常工作。现在,我建议不要将Task.FromResult
与async
函数一起使用。
相反,我应该使用类似的东西:
var innerValue = await value; //..this works fine too
但我不确定为什么第一个不是一个很好的做法来完成同样的事情。 任何线索都会有所帮助。 感谢
答案 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;
或者,如果在value
和innerValue
之间没有代码可以运行,则可以完全忽略value
的分配
var innerValue = await this.SomeFunction(...);