TPL和async/await之间的区别(线程处理)

cod*_*fun 61 multithreading task-parallel-library async-await c#-5.0

尝试理解TPL和async/ await在线程创建方面的区别.

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

我认为async/ await会以同样的方式工作:

TPL:

Factory.StartNew( () => DoSomeAsyncWork() )
.ContinueWith( 
    (antecedent) => {
        DoSomeWorkAfter(); 
    },TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)

Async/ Await:

await DoSomeAsyncWork();  
DoSomeWorkAfter();
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*ary 76

我相信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,所以上面的规则有例外.

注意,默认的Taskawaiter 如果它不为null,async将在当前方法上调度方法的其余部分; 否则它继续流行.这在今天并不那么重要,但在不久的将来它将是一个重要的区别.SynchronizationContext TaskScheduler

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

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

  • 很好的答案。我还推荐 http://www.infoq.com/articles/Async-API-Design 和这个出色的演示文稿:http://channel9.msdn.com/Events/TechEd/Europe/2013/DEV-B318。 (2认同)

Nic*_*ler 8

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

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

所以,C#5版本将是:

await Task.Run( () => DoSomeAsyncWork() );
DoSomeWorkAfter();
Run Code Online (Sandbox Code Playgroud)