zil*_*n01 61 c# task-parallel-library async-await c#-5.0
我没有看到C#(和VB)的新异步功能和.NET 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);
}
}
Run Code Online (Sandbox Code Playgroud)
似乎该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
}
}
Run Code Online (Sandbox Code Playgroud)
我已经将第await一个替换Task.Result为实际需要值的位置,第二个await替换Task.Wait()为实际发生等待的位置.该功能(1)已经实现,并且(2)在语义上与代码中实际发生的内容更加接近.
我确实意识到一个async方法被重写为状态机,类似于迭代器,但我也看不出它带来了什么好处.任何需要另一个线程运行的代码(例如下载)仍然需要另一个线程,任何不需要的代码(例如从文件中读取)仍然可以利用TPL只使用一个线程.
我显然遗失了一些巨大的东西; 任何人都可以帮助我更好地理解这一点吗?
Ree*_*sey 71
我认为这里出现了误解:
似乎await关键字有两个不同的用途.第一次出现(FetchAsync)似乎意味着,"如果稍后在方法中使用此值并且其任务未完成,请等到它完成后再继续." 第二个实例(存档)似乎意味着,"如果此任务尚未完成,请立即等待直到完成." 如果我错了,请纠正我.
这实际上是完全错误的.这两者具有相同的含义.
在你的第一个案例中:
var document = await FetchAsync(urls[i]);
Run Code Online (Sandbox Code Playgroud)
这里发生的是运行时说"开始调用FetchAsync,然后将当前执行点返回给调用此方法的线程." 这里没有"等待" - 相反,执行返回到调用同步上下文,并且事情继续搅动.在将来的某个时刻,FetchAsync的任务将完成,此时,此代码将在调用线程的同步上下文中恢复,并且将发生下一个语句(分配文档变量).
执行将继续,直到第二次等待调用 - 此时,同样的事情将发生 - 如果Task<T> (存档)未完成,执行将被释放到调用上下文 - 否则,将设置存档.
在第二种情况下,事情是非常不同的 - 在这里,你明确地阻塞,这意味着在整个方法完成之前,调用同步上下文永远不会有机会执行任何代码.当然,仍然存在异步,但是异步完全包含在这个代码块中 - 在此线程之外的代码之外不会发生任何代码,直到所有代码完成.
Dan*_*iel 25
这是个很大的差异:
Wait()块,await不阻止.如果ArchiveDocuments() 在GUI线程上运行异步版本,GUI将在提取和归档操作运行时保持响应.如果您使用TPL版本Wait(),您的GUI将被阻止.
注意,async设法在不引入任何线程的情况下执行此操作 - 在await控制点处,简单地返回到消息循环.一旦等待的任务完成,该方法的其余部分(继续)将在消息循环中排队,并且GUI线程将继续ArchiveDocuments在其停止的位置运行.
Bra*_*ham 24
在他所做的第9频道直播采访中,安德斯将其归结为一个非常简洁的答案.我强烈推荐它
新的Async和await关键字允许您在应用程序中协调并发.它们实际上并没有在您的应用程序中引入任何并发性.
TPL,更具体地说,Task是一种可以用来同时实际执行操作的方法.新的async和await关键字允许您以"同步"或"线性"方式组合这些并发操作.
因此,您仍然可以在程序中编写线性控制流,而实际计算可能会同时发生也可能不会同时发生.当计算同时发生时,await和async允许您组合这些操作.
| 归档时间: |
|
| 查看次数: |
14856 次 |
| 最近记录: |