c# - C# 5.0 的异步等待功能与 TPL 有何不同?

标签 c# task-parallel-library c#-5.0 async-await

我看不出 C#(和 VB)的新异步特性和 .NET 4.0 的 Task Parallel Library 之间有什么不同.以 Eric Lippert 的代码 from here 为例:

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 仅与单个线程一起工作。

我显然在这里遗漏了一些重要的东西;谁能帮助我更好地理解这一点?

最佳答案

我认为误解出现在这里:

It seems that the await keyword is serving two different purposes. The first occurrence (FetchAsync) seems to mean, "If this value is used later in the method and its task isn't finished, wait until it completes before continuing." The second instance (archive) seems to mean, "If this task is not yet finished, wait right now until it completes." If I'm wrong, please correct me.

这实际上是完全错误的。两者含义相同。

在你的第一种情况下:

var document = await FetchAsync(urls[i]);

这里发生的事情是,运行时说“开始调用 FetchAsync,然后将当前执行点返回给调用此方法的线程。”这里没有“等待”——相反,执行返回到调用同步上下文,并且事情一直在搅动。在未来的某个时刻,FetchAsync 的 Task 将完成,此时,此代码将在调用线程的同步上下文中恢复,并且下一个语句(分配文档变量)将发生。

然后执行将继续,直到第二次等待调用 - 此时,同样的事情会发生 - 如果 Task<T> (存档)未完成,执行将被释放到调用上下文 - 否则,存档将被设置。

在第二种情况下,情况非常不同 - 在这里,您显式阻塞,这意味着调用同步上下文永远不会有机会执行任何代码,直到您的整个方法完成。当然,仍然存在异步,但异步完全包含在此代码块中 - 在您的所有代码完成之前,此线程上不会发生此粘贴代码之外的任何代码。

关于c# - C# 5.0 的异步等待功能与 TPL 有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4054263/

相关文章:

loops - 循环中的异步和等待多个任务,如何返回单个任务

c# - C#中特性标志的实现

c# - 点网核心: can't run unit tests

c# - 任务吞下抛出的异常

c# - 如何检测循环中的任务

windows-8 - 如何在注册后立即启动 Windows 应用后台任务?

c# - SqlDataReader 已经在不同的命令中打开

c# - 在运行时即时更改应用程序语言

c# - 如果存在,则在 gridview 的特定列中突出显示 SQL 表中存在的关键字

c# - 并发网络请求性能问题