Вероятно, наиболее важным различием между параллельными расширениями и обычным потоком является поток управления.
Поток, созданный с использованием new Thread(...)
или ThreadPool.QueueUserWorkItem
, завершится в совершенно неопределенный момент времени. Если вы напишите этот код:
ThreadPool.QueueUserWorkItem(() =>
{
Thread.Sleep(1000);
Console.WriteLine("Work Finished");
});
Console.WriteLine("Item Queued");
Текст Item Queued
появится сразу, а Work Finished
будет напечатан примерно через 1 секунду.
С другой стороны, если вы пишете нечто подобное с использованием параллельных расширений:
Parallel.For(0, 10, i =>
{
Thread.Sleep(1000);
Console.WriteLine("Test {0}", i);
});
Console.WriteLine("Finished");
В этом случае вы увидите задержку в 1 секунду, прежде чем что-либо произойдет, затем набор «тестовых» сообщений в произвольном порядке и , затем текст Finished
.
Другими словами, параллельное выполнение задач на самом деле не влияет на ход программы. Он будет запускать разные задачи в разных потоках, чтобы их можно было выполнять на нескольких ядрах ЦП, чтобы улучшить общую пропускную способность программы, но для обычного программиста эти задачи на самом деле не выполняются в "фоновом режиме". «как они были бы с резьбой. Вам не нужно менять структуру вашей программы или делать что-то особенное, чтобы получать уведомления о завершении работы. У вас нет контроля над тем, что происходит внутри параллельного блока, но вы точно знаете, что блок не вернет управление, пока все параллельные задачи не будут завершены.
Хотя Parallel Extensions отлично подходят для этого, стоит упомянуть, что PX вообще бесполезен, когда на самом деле требуется для запуска задачи в фоновом режиме, такой как реализация планировщика или делегирование в рабочий поток чтобы пользовательский интерфейс был отзывчивым. Вам все еще нужно использовать потоки или асинхронные компоненты для них.