试图理解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线程。
答案 0 :(得分:71)
我相信TPL(TaskFactory.Startnew)的工作方式类似于ThreadPool.QueueUserWorkItem,因为它在线程池中的一个线程上排队工作。
从我一直在阅读的内容看来,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
:
任何线程都可以设置自己的SynchronizationContext
,因此上述规则有例外。
请注意,默认Task
等待者会在当前async
上安排SynchronizationContext
方法的剩余部分,如果它不为空;否则它继续当前的TaskScheduler
。这在今天并不那么重要,但在不久的将来它将是一个重要的区别。
我在自己的博客上写了自己的async
/await
intro,而Stephen Toub最近发布了一篇优秀的async
/await
FAQ。
关于“并发”与“多线程”,请参阅this related SO question。我会说async
启用并发,这可能是也可能不是多线程的。使用await Task.WhenAll
或await Task.WhenAny
进行并发处理很容易,除非您明确使用线程池(例如Task.Run
或ConfigureAwait(false)
),否则可以有多个并发同时进行的操作(例如,多个I / O或其他类型,如Delay
) - 并且它们不需要线程。我在这种情况下使用术语“单线程并发”,但在ASP.NET主机中,实际上最终可以得到“零 - 线程并发”。这很可爱。
答案 1 :(得分:8)
async / await基本上简化了ContinueWith
方法(Continuation Passing Style中的延续)
它不引入并发性 - 你仍然必须自己做(或者使用框架方法的异步版本。)
所以,C#5版本将是:
await Task.Run( () => DoSomeAsyncWork() );
DoSomeWorkAfter();