如何C#5.0是异步的等待着特征不同于TPL?
-
27-09-2019 - |
题
我不要看到不同之间C#'s(和VB的)新的异步的特征。净4.0 任务并行的图书馆.采取,例如,埃里克利珀特的代码 从这里:
async void ArchiveDocuments(List<Url> urls) {
Task archive = null;
for(int i = 0; i < urls.Count; ++i) {
var document = await FetchAsync(urls[i]);
if (archive != null)
await archive;
archive = ArchiveAsync(document);
}
}
似乎这 await
关键字是服务于两个不同的目的。第一次出现(FetchAsync
)似乎意味, "如果使用此值 在后面的方法 它的任务还没结束,等待,直到它完成之前,仍在继续。" 第二个实例(archive
)似乎意味, "如果这项任务尚未完成,等等 现在 直到完成。" 如果我错了,请纠正我。
不能它只是作为容易地被写入这样吗?
void ArchiveDocuments(List<Url> urls) {
for(int i = 0; i < urls.Count; ++i) {
var document = FetchAsync(urls[i]); // removed await
if (archive != null)
archive.Wait(); // changed to .Wait()
archive = ArchiveAsync(document.Result); // added .Result
}
}
我已经替换第一 await
与 Task.Result
其中值实际需要,第二 await
与 Task.Wait()
, ,在那里等待,实际上是存在的。该功能 (1)
已经实施, (2)
更接近在语义上对实际发生了什么代码。
我知道一个 async
方法是改写作为一个国家机,类似于迭代,但是我也看不到什么好处就带来的。任何代码,需要另外一个线程的操作(例如下载)将仍然需要另外一个线程,以及任何代码,不(例如从阅读一个文件),仍然可以利用的TPL的工作只有一个单一的线。
我显然缺失的东西巨大;有人能帮我了解这个好一点?
解决方案
我觉得误会就出现在这里:
看来,AWAIT关键字服务两个不同的目的。第一次出现(FetchAsync)似乎意味着,“如果此值的方法后使用,直到其继续之前完成其任务未完成,等待。”第二个实例(存档)似乎意味着,“如果这个任务还没有完成,现在直到它完成等待。”如果我错了,请大家指正。
这实际上是完全不正确。这两个具有相同的含义。
在您的第一种情况:
var document = await FetchAsync(urls[i]);
在这里会发生什么事,是运行时表示,“开始打电话FetchAsync,那么当前执行点返回线程调用此方法。”有没有“等待”在这里 - 相反,执行返回到调用同步上下文,事情不断翻腾。在未来的某个时刻,FetchAsync的任务将完成,而在这一点上,该代码将恢复调用线程的同步上下文,并会出现下一个语句(分配文件变量)。
执行会再继续,直到第二的await呼叫 - 此时,同样的事情会发生 - 如果Task<T>
(归档)是不完整的,执行将被释放到调用上下文 - 否则,存档将被设置
在第二种情况下,事情有很大的不同 - 在这里,你明确阻止,这意味着调用同步上下文将没有机会执行任何代码,直到你的整个方法完成。当然,仍有不同步,但不同步时的代码块完全包含 - 无码的这种粘贴代码将发生在这个线程,直到所有的代码完成外
其他提示
有巨大的差异:
Wait()
块,await
不会阻塞。如果您在GUI线程中运行ArchiveDocuments()
的异步版本,GUI会同时获取和归档的操作时保持响应。
如果您使用的Wait()
TPL版本,您的GUI将被阻止。
请注意async
设法做到这一点没有引入任何线程 - 在await
的点时,控制简单地返回到消息循环。一旦任务被等待已经完成,则该方法(续)的剩余部分被入队的消息循环和GUI线程将继续运行ArchiveDocuments
它离开的地方。
安德斯煮下来到他做的第9频道现场采访了非常简洁的回答。我强烈推荐它
在新的异步伺机关键字允许你的编排并发在您的应用程序。他们实际上不引入到应用程序的任何并发性。
TPL和更具体的任务是 单向的:您可以使用实际并行地执行操作。新的异步并等待关键字允许您的撰写强>在“同步”或这些并发操作“线性”的方式。
所以,你仍然可以写控制在你的程序的流线性,而实际计算可能会或可能不会同时发生。计算时不同时发生,待机和异步让你的撰写这些操作。
转控制的程序流进的状态机的能力是什么使这些新关键字intresting。把它看成是的得到控制下,而不是值。
检查出的Anders谈论的此第9频道影片新的功能。
这里的问题是,ArchiveDocuments
的签名是误导。它有void
一个明确的回报,但真正的回报是Task
。对我来说意味着无效同步,因为没有办法“等待”它完成。考虑功能的替代签名。
async Task ArchiveDocuments(List<Url> urls) {
...
}
要我当它是这样写的区别是明显得多。该ArchiveDocuments
功能是不是一个同步完成,但后来将完成。
要FetchAsync()
呼叫仍将会阻塞,直到它完成(除非呼叫await
内声明?)的关键是控制返回给调用者(因为ArchiveDocuments
方法本身被声明为async
)。因此,主叫方可以愉快地继续处理UI逻辑,响应事件,等
当FetchAsync()
完成,它将中断调用者完成循环。它击中ArchiveAsync()
和盖帽,但ArchiveAsync()
可能只是创建了一个新的任务,启动它,并返回任务。这允许第二循环开始,而任务处理。
在第二环路命中FetchAsync()
和块,将控制返回给调用者。当FetchAsync()
完成,它再一次打断来电者继续处理。然后射await archive
,其将控制返回给调用者,直到环1完成创建Task
。一旦任务完成后,主叫方再次中断,而第二循环调用ArchiveAsync()
,它得到一个启动任务并开始循环3,重复的广告nauseum 的。
的关键是而重升降器执行返回控制给调用者。
等待关键词不会引入并发。它更像是产率的关键词,告诉编译器,调整你的代码转lambda通过一个控制国家机器。
看看有什么在等待着代码会看起来像没有'待看到这个优秀的链接: http://blogs.msdn.com/b/windowsappdev/archive/2012/04/24/diving-deep-with-winrt-and-await.aspx