我不要看到不同之间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
    }
}

我已经替换第一 awaitTask.Result 其中值实际需要,第二 awaitTask.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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top