我相信 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
的其余部分调度;否则它继续当前。这在今天并不那么重要,但在不久的将来它将是一个重要的区别。async
SynchronizationContext
TaskScheduler
我在我的博客上写了我自己的async
/await
介绍,Stephen Toub 最近发布了一篇优秀的async
/await
常见问题解答。
关于“并发”与“多线程”,请参阅这个相关的 SO question。我会说async
启用并发,这可能是也可能不是多线程的。它易于使用await Task.WhenAll
或await Task.WhenAny
进行并发处理,除非您明确使用线程池(例如,Task.Run
或ConfigureAwait(false)
),否则您可以同时进行多个并发操作(例如,多个 I/O 或其他类型,例如Delay
)-他们不需要线程。对于这种情况,我使用术语“单线程并发”,尽管在 ASP.NET 主机中,您实际上可以得到“零线程并发”。这很甜蜜。