我相信 TPL (TaskFactory.Startnew) 的工作方式与 ThreadPool.QueueUserWorkItem 类似,因为它在线程池中的线程上排队工作。
差不多.
从我读到的内容来看,异步/等待似乎只是“有时”创建一个新线程。
事实上,它永远不会。如果想要多线程,就得自己实现。有一个新的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
can be await
ed - 它不一定是async
方法。所以Task.Delay
和 I/O 密集型操作只需使用TaskCompletionSource
创建并完成任务 - 线程池上执行的唯一操作是事件发生时的实际任务完成(超时、I/O 完成等)。
我想我对 FromCurrentSynchronizationContext 的理解也总是有点模糊。我一直认为它本质上是 UI 线程。
I wrote 一篇文章 on SynchronizationContext
。大多数时候,SynchronizationContext.Current
:
- 如果当前线程是 UI 线程,则为 UI 上下文。
- 如果当前线程正在为 ASP.NET 请求提供服务,则为 ASP.NET 请求上下文。
- 否则是线程池上下文。
任何线程can设置自己的SynchronizationContext
,因此上述规则也有例外情况。
请注意,默认Task
等待者将安排剩余的时间async
方法对当前SynchronizationContext
如果它不为空;否则它会继续当前的状态TaskScheduler
。这在今天并不那么重要,但在不久的将来它将成为一个重要的区别。
我自己写的async/await intro在我的博客上,Stephen Toub 最近发布了一篇出色的文章async/await FAQ.
关于“并发”与“多线程”,请参见这个相关的SO问题。我会说async
启用并发,它可能是多线程的,也可能不是。很容易使用await Task.WhenAll
or await Task.WhenAny
进行并发处理,除非您明确使用线程池(例如,Task.Run
or ConfigureAwait(false)
),那么您可以同时进行多个并发操作(例如,多个 I/O 或其他类型,如Delay
) - 并且它们不需要线程。对于这种情况,我使用术语“单线程并发”,尽管在 ASP.NET 主机中,您实际上可能会得到“zero-线程并发”。这非常贴心。