我在网上搜索过很多关于Task.Run和await async的问题,但是有一个特定的使用场景,我并不是真的理解其中的区别。我相信情况很简单。
await Task.Run(() => LongProcess());vs
await LongProcess());其中LongProcess是一种异步方法,其中包含一些异步调用,例如使用await ExecuteReaderAsync()调用db。
问题:
在这种情况下,两者之间有什么不同吗?感谢任何帮助或意见,谢谢!
发布于 2016-08-03 17:20:54
Task.Run可能会将操作发布到不同的线程进行处理。这是唯一的区别。
这可能很有用-例如,如果LongProcess不是真正异步的,它将使调用者更快地返回。但是对于真正的异步方法,使用Task.Run是没有意义的,而且可能会造成不必要的浪费。
不过要小心,因为Task.Run的行为将根据重载解决方案而改变。在您的示例中,将选择Func<Task>重载,它将(正确地)等待LongProcess完成。但是,如果使用了非任务返回的委托,Task.Run将只等待执行到第一个await (请注意,这是TaskFactory.StartNew的行为方式,所以不要使用它)。
发布于 2016-08-04 04:29:26
通常人们认为异步等待是由多个线程完成的。事实上,这一切都是由一个线程完成的。
请参阅下面有关单线程语句的附加内容
对我理解异步等待有很大帮助的是this interview with Eric Lippert about async-await。在中间的某个地方,他将async await比作一个必须等待水烧开的厨师。他不是什么也不做,而是环顾四周,看看是否还有其他事情要做,比如切洋葱。如果做完了,水还没有烧开,他就会检查是否有其他事情要做,依此类推,直到他除了等待什么也没做为止。在这种情况下,他返回到他等待的第一件事。
如果你的过程调用了一个可等待的函数,我们可以确定在这个可等待的函数中的某个地方有一个对可等待函数的调用,否则这个函数就不会被等待。事实上,如果你在可等待的函数中忘记等待,你的编译器会警告你。
如果您的可等待函数调用另一个可等待函数,则线程将进入另一个函数,并开始执行此函数中的操作,然后深入其他函数,直到遇到等待。
而不是等待结果,线程在他的调用堆栈中向上移动,看看是否有其他他可以处理的代码片段,直到他看到等待。在调用堆栈中再次向上,处理直到等待,等等。一旦每个人都在等待,线程将查找底部等待,并在完成后继续。
这样做的好处是,如果可等待函数的调用者不需要函数的结果,但可以在需要结果之前做其他事情,这些其他事情可以由线程完成,而不是在函数中等待。
不立即等待结果的呼叫将如下所示:
private async Task MyFunction()
{
Task<ReturnType>taskA = SomeFunctionAsync(...)
// I don't need the result yet, I can do something else
DoSomethingElse();
// now I need the result of SomeFunctionAsync, await for it:
ReturnType result = await TaskA;
// now you can use object result
}请注意,在此场景中,所有操作都由一个线程完成。只要你的线程有事情要做,他就会很忙。
Addition.并不是只涉及一个线程。任何无事可做的线程都可以在等待之后继续处理您的代码。如果你检查线程id,你可以看到在await之后这个id是可以改变的。连续线程具有与原始线程相同的
context,因此您可以将其视为原始线程。不需要检查InvokeRequired,不需要使用互斥锁或临界区。对于您的代码,这就好像涉及到了一个线程。
本答案末尾的文章链接解释了有关线程上下文的更多信息
您将看到可等待的函数,其中主要是其他进程必须执行的操作,而您的线程只需空闲地等待,直到其他操作完成。例如,通过互联网发送数据、保存文件、与数据库通信等。
然而,有时必须完成一些繁重的计算,并且您希望线程可以自由地做其他事情,比如响应用户输入。在这种情况下,您可以启动一个可等待的操作,就像调用一个异步函数一样。
Task<ResultType> LetSomeoneDoHeavyCalculations(...)
{
DoSomePreparations()
// start a different thread that does the heavy calculations:
var myTask = Task.Run( () => DoHeavyCalculations(...))
// now you are free to do other things
DoSomethingElse();
// once you need the result of the HeavyCalculations await for it
var myResult = await myTask;
// use myResult
...
}现在,一个不同的线程正在做繁重的计算,而你的线程可以自由地做其他事情。一旦它开始等待,你的调用者就可以做一些事情,直到他开始等待。有效地,您的线程将相当自由地对用户输入做出反应。然而,只有在每个人都在等待的情况下才会出现这种情况。当你的线程忙于做一些事情时,你的线程不能对用户输入做出反应。因此,请务必确保,如果您认为您的UI线程必须执行一些需要花费一些时间的繁忙处理,请使用Task.Run并让另一个线程来完成
另一篇对我有帮助的文章:Async-Await by the brilliant explainer Stephen Cleary
https://stackoverflow.com/questions/38739403
复制相似问题