73

在线程创建方面 试图理解 TPL & async/之间的区别。await

我相信 TPL ( TaskFactory.StartNew) 的工作方式类似于ThreadPool.QueueUserWorkItem它在线程池中的线程上排队工作。当然,除非您使用TaskCreationOptions.LongRunningwhich 创建一个新线程。

我认为async/await本质上会类似地工作:

TPL:

Factory.StartNew( () => DoSomeAsyncWork() )
.ContinueWith( 
    (antecedent) => {
        DoSomeWorkAfter(); 
    },TaskScheduler.FromCurrentSynchronizationContext());

Async/ Await:

await DoSomeAsyncWork();  
DoSomeWorkAfter();

将是相同的。从我一直在阅读的内容来看,似乎async/await只有“有时”会创建一个新线程。那么它什么时候创建一个新线程,什么时候不创建一个新线程呢?如果您正在处理 IO 完成端口,我可以看到它不必创建新线程,否则我认为它必须这样做。我想我对FromCurrentSynchronizationContextalways的理解也有点模糊。我一直认为它本质上是 UI 线程。

4

2 回答 2

86

我相信 TPL (TaskFactory.Startnew) 的工作方式与 ThreadPool.QueueUserWorkItem 类似,因为它将线程池中线程上的工作排队。

差不多

从我一直在阅读的内容来看,似乎 async/await 仅“有时”会创建一个新线程。

实际上,它永远不会。如果你想要多线程,你必须自己实现它。有一种新Task.Run方法只是 的简写Task.Factory.StartNew,它可能是在线程池上启动任务的最常用方法。

如果您正在处理 IO 完成端口,我可以看到它不必创建一个新线程,但否则我认为它必须这样做。

答对了。所以像这样的方法Stream.ReadAsync实际上会Task在 IOCP 周围创建一个包装器(如果Stream有 IOCP)。

您还可以创建一些非 I/O、非 CPU 的“任务”。一个简单的例子是Task.Delay,它返回一个在一段时间后完成的任务。

async/很酷的一点await是,您可以将一些工作排​​队到线程池(例如,Task.Run),执行一些 I/O 绑定操作(例如,Stream.ReadAsync),并执行一些其他操作(例如,Task.Delay)......而且它们是所有任务!它们可以等待或组合使用,例如Task.WhenAll.

Task可以编辑任何返回的方法await- 它不必是async方法。因此Task.Delay,I/O 绑定操作仅用于TaskCompletionSource创建和完成任务——线程池上唯一要做的事情是事件发生时的实际任务完成(超时、I/O 完成等)。

我想我对 FromCurrentSynchronizationContext 的理解也总是有点模糊。我一直认为它本质上是 UI 线程。

我写了一篇关于SynchronizationContext. 大多数时候,SynchronizationContext.Current

  • 如果当前线程是 UI 线程,则为 UI 上下文。
  • 如果当前线程正在为 ASP.NET 请求提供服务,则为 ASP.NET 请求上下文。
  • 否则是线程池上下文。

任何线程都可以设置自己的SynchronizationContext,因此上述规则也有例外。

请注意,如果它不为 null ,则默认等待者将在当前方法Task的其余部分调度;否则它继续当前。这在今天并不那么重要,但在不久的将来它将是一个重要的区别。asyncSynchronizationContext TaskScheduler

我在我的博客上写了我自己的async/await介绍,Stephen Toub 最近发布了一篇优秀的async/await常见问题解答

关于“并发”与“多线程”,请参阅这个相关的 SO question。我会说async启用并发,这可能是也可能不是多线程的。它易于使用await Task.WhenAllawait Task.WhenAny进行并发处理,除非您明确使用线程池(例如,Task.RunConfigureAwait(false)),否则您可以同时进行多个并发操作(例如,多个 I/O 或其他类型,例如Delay)-他们不需要线程。对于这种情况,我使用术语“单线程并发”,尽管在 ASP.NET 主机中,您实际上可以得到“线程并发”。这很甜蜜。

于 2012-04-23T18:56:51.603 回答
9

async / await 基本上简化了ContinueWith方法(Continuations in Continuation Passing Style

它没有引入并发——你仍然需要自己做(或者使用框架方法的异步版本。)

因此,C# 5 版本将是:

await Task.Run( () => DoSomeAsyncWork() );
DoSomeWorkAfter();
于 2012-04-23T17:27:39.360 回答