我认为 TPL(TaskFactory.Startnew)与 ThreadPool.QueueUserWorkItem 类似,都是在线程池中排队等待工作。
基本上是这样。
根据我所了解的,异步/等待似乎只有“有时”才会创建新线程。
实际上,它从未创建过。如果您想要多线程,则必须自己实现。有一个新的 Task.Run
方法只是 Task.Factory.StartNew
的简写,这可能是在线程池上启动任务的最常见方法。
如果你处理IO完成端口,我可以看到它不必创建新线程,但否则我认为它必须这样做。
Bingo。因此,像 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/O完成等)时,唯一在线程池上执行的就是实际的任务完成。
我想我对FromCurrentSynchronizationContext的理解一直有点模糊。我总是认为它本质上是UI线程。
我写了一篇关于
SynchronizationContext
的文章
an article。大部分时间,
SynchronizationContext.Current
:
- 如果当前线程是 UI 线程,则为 UI 上下文。
- 如果当前线程正在服务一个 ASP.NET 请求,则为 ASP.NET 请求上下文。
- 否则为线程池上下文。
任何线程都可以设置自己的 SynchronizationContext
,因此上述规则也有例外情况。
请注意,默认的 Task
等待程序会在当前 SynchronizationContext
不为空时将剩余的 async
方法安排在其中;否则它会在当前的 TaskScheduler
中进行。这对今天来说并不那么重要,但在不久的将来,这将是一个重要的区别。
我在我的博客上写了一篇关于async
/await
介绍的文章,而Stephen Toub最近发布了一个优秀的async
/await
常见问题解答。
关于“并发”和“多线程”,请参阅
这个相关的SO问题。我会说
async
实现了并发,但不一定是多线程的。使用
await Task.WhenAll
或
await Task.WhenAny
很容易实现并发处理,除非您明确地使用线程池(例如
Task.Run
或
ConfigureAwait(false)
),否则可以同时进行多个并发操作(例如多个I/O或其他类型,如
Delay
)-而且它们不需要线程。我将这种情况称为“单线程并发”,尽管在ASP.NET主机中,您实际上可以获得“零线程并发”。这相当棒。
TaskCreationOptions.LongRunning
时,实际上总是会创建一个新的专用线程。 - Zaid MasudThread.CurrentThread.IsThreadPoolThread
返回true。更不用说我使用的ThreadStatic变量渗透到多个线程中,导致各种混乱。我不得不强制我的代码新建多个Thread(),以保证专用线程。换句话说,我不能使用TaskFactory来获得专用线程。或者,您可以实现自己的TaskScheduler
,始终返回专用线程。 - eduncan911