我相信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
都可以await
编辑-不必一定是async
方法。因此,Task.Delay
与I / O绑定的操作仅用于TaskCompletionSource
创建和完成任务-在线程池上唯一要做的事情是事件发生时的实际任务完成(超时,I / O完成等)。
我想我对FromCurrentSynchronizationContext的理解也总是有点模糊。从本质上讲,我始终认为它是UI线程。
我写了一篇文章上SynchronizationContext
。大多数时候SynchronizationContext.Current
:
- 如果当前线程是UI线程,则是UI上下文。
- 如果当前线程正在为ASP.NET请求提供服务,则为ASP.NET请求上下文。
- 否则为线程池上下文。
任何线程都可以设置自己的线程SynchronizationContext
,因此上述规则也有例外。
请注意,如果默认的Task
等待者不为null,它将async
在当前方法上调度方法的其余部分;否则它会在当前SynchronizationContext
TaskScheduler
。今天这并不是很重要,但是在不久的将来,这将是一个重要的区别。
我在自己的博客上写了自己的async
/await
介绍,而Stephen Toub最近发布了一个出色的async
/await
常见问题解答。
关于“并发”与“多线程”,请参阅此相关的SO问题。我会说async
启用并发,它可能是多线程的,也可能不是。使用await Task.WhenAll
或await Task.WhenAny
执行并发处理都很容易,除非您显式使用线程池(例如Task.Run
或ConfigureAwait(false)
),否则您可以同时进行多个并发操作(例如,多个I / O或其他类型,例如Delay
)-而且它们不需要线程。在这种情况下,我使用术语“单线程并发”,尽管在ASP.NET主机中,实际上可以得到“零线程并发”。真是太好了