Из статьи
regfordev.blogspot.ru/2010/12/thread-pool.html
Абзац 1:
Новый пул потоков работает немного другим образом. Для каждого рабочего потока в пуле существует своя локальная очередь. Задача, которая попала в локальную очередь, может породить дочернюю и они размещаются в эту же локальную очередь. Также задачи выполняются в локальной очереди в LIFO (last-in-first-out) порядке, в отличие от пула в 3.5, где задачи из глобальной очереди выполняются рабочими потоками в FIFO (first-in-first-out) порядке. Так как только рабочий поток разгребает свою собственную кучу, вернее имеет доступ к ее началу (head), то на уровне локальной очереди не требуется никаких синхронизаций.
Абзац 2:
Когда рабочий поток видит что делать ему больше нечего, то есть его локальная очередь пустая, он пытается своровать задачу у другого рабочего потока. Но ворует он элементы с хвоста чужой локальной очереди.
Пытаюсь понять, что тут имеется ввиду. Предположим, что ситуация из абзаца 2 не случится (все потоки всегда будут заняты). То есть, как следует из абзаца 1, в этом случае, если мой код, выполняющий родительскую задачу (поток #1), создает новую параллельную дочернюю задачу через вызов Task.Run , то фактически дочерняя задача не запустится параллельно в другом потоке, а будет запущена в том же потоке #1, который поставил ее в очередь, уже после того, как поток #1 закончит выполнение родительской задачи? И по сути мы получим просто последовательное выполнение задач?
Если так, то тут же нет никакого параллельного выполнения задач. Для чего тогда тут использование Task.Run, когда можно тупо просто выполнить родительскую и дочернюю задачи последовательно друг другом в одном потоке?
Или предполагается, что ситуация, когда все потоки заняты, очень редкая, и фактически задача из Task.Run чаще всего будет запущена в отдельном потоке параллельно?
Или я вообще что-то не так понял? Объясните.