TPL与TPL之间的差异async / await(线程处理)

时间:2012-04-23 17:20:38

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

试图理解TPL和amp;之间的区别。关于线程创建,async / await

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

我认为async / await的工作方式基本相同:

TPL:

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

Async / Await

await DoSomeAsyncWork();  
DoSomeWorkAfter();

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

2 个答案:

答案 0 :(得分:71)

  

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

Pretty much

  

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

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

  

如果您正在处理IO完成端口,我可以看到它不必创建新线程,否则我认为它将不得不。

宾果。因此,像Stream.ReadAsync这样的方法实际上会在IOCP周围创建一个Task包装器(如果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 /完成等)。

  

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

我在SynchronizationContext上写了an article。大多数情况下,SynchronizationContext.Current

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

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

请注意,默认Task等待者会在当前async 上安排SynchronizationContext方法的剩余部分,如果它不为空;否则它继续当前的TaskScheduler。这在今天并不那么重要,但在不久的将来它将是一个重要的区别。

我在自己的博客上写了自己的async/await intro,而Stephen Toub最近发布了一篇优秀的async/await FAQ

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

答案 1 :(得分:8)

async / await基本上简化了ContinueWith方法(Continuation Passing Style中的延续)

它不引入并发性 - 你仍然必须自己做(或者使用框架方法的异步版本。)

所以,C#5版本将是:

await Task.Run( () => DoSomeAsyncWork() );
DoSomeWorkAfter();