我正在阅读有关Thread和Task之间差异的问题。我得到了这个链接:Task Schedulers on MSDN。
但我对这一段感到困惑:
在某些情况下,当等待任务时,可以在执行等待操作的线程上同步执行。这提高了性能,因为它可以通过利用已经阻塞的现有线程来防止需要额外的线程,否则。 为了防止由于重新入侵而导致的错误,只有在相关线程的本地队列中找到等待目标时才会发生任务内联。
我想了解突出显示的部分。此外,我本地缓存和全局队列也有点混乱...我真的很好奇理解TaskScheduler ... 请帮忙..
答案 0 :(得分:2)
首先,本地和全球队列是什么?这是.Net 4.0中并行处理的优化。如果你有很多小的Task
和只有一个全局队列,你会得到很多争论。那是因为所有线程都在从同一个地方(全局队列的前面)处理Task
,并且它们也将新的Task
放在同一个地方(全局队列的后面) 。这需要线程之间的大量同步,这可能会影响性能。
.Net 4.0中的TPL使用了一种称为“工作窃取”的技术:有一个全局队列,和以前一样,每个ThreadPool
工作线程(但不是其他线程)也有一个本地队列。如果非工作线程启动Task
,它将像以前一样进入全局队列的后面。如果工作线程启动Task
,它将转到其本地队列的后面。
现在到了有趣的部分。如果工作线程应该处理新的Task
,它会在这些地方查找它(按此顺序):
最后一部分是为什么这称为“工作窃取”:工作线程可以“窃取”Task
从另一个线程进行处理。线程不需要使用同步来访问其本地队列的后端,因为没有其他线程可以访问它。在本地以LIFO顺序处理Task
也适用于缓存,因为最后Task
(以及它使用的数据)最有可能仍在CPU缓存中。
有关所有这些内容的另一种解释(附图片),请参阅Work-Stealing in .NET 4.0。
这需要做什么内联和reentrancy?我不知道。如果Task
使用了一些线程静态字段,我可以理解为什么可能存在重入问题,但这与队列无关。无论内联Task
来自哪个队列,都可能发生此问题。我无法想到本地队列中Task
保证内联安全的任何情况,但来自其他队列的Task
可能不安全。
答案 1 :(得分:2)
本地/全局队列术语最初来自ThreadPool内部,基于ThreadPool的TaskScheduler,因此术语相同...在MSDN上阅读更多内容:ThreadPool Global Queue vs. Local Queues。另外svick的答案很大程度上描述了这一点。
为了防止由于重新入侵而导致的错误,任务内联仅在发生时发生 等待目标位于相关线程的本地队列中。
我认为等待目标是一个阻塞线程的WaitHandle实例。因此,如果在等待线程的lcoal队列中找到WaitHandle实例 - 它将自动被视为内联任务的本地队列项。
请尽快阅读Stephen Toub撰写的Task.Wait and “Inlining”文章,以清楚地描述这一过程。