Создание потоков - Task.Factory.StartNew vs new Thread ()

102

Я только изучаю новые библиотеки Threading и Parallel в .Net 4

Раньше я бы создал новый поток, например, так (в качестве примера):

DataInThread = new Thread(new ThreadStart(ThreadProcedure));
DataInThread.IsBackground = true;
DataInThread.Start();

Теперь я могу:

Task t = Task.Factory.StartNew(() =>
{
   ThreadProcedure();
});

В чем разница, если она есть?

Спасибо

Джон
источник
1
Вам нужно немного побеспокоиться о том, как работает планировщик пула потоков. Это может иметь большое значение, но все зависит от того, что вы на самом деле делаете внутри потока.
Ханс Пассан

Ответы:

79

Существует большая разница. Задачи планируются в ThreadPool и могут даже выполняться синхронно, если это необходимо.

Если у вас есть длительная фоновая работа, вы должны указать это, используя правильный параметр задачи.

Вам следует предпочесть параллельную библиотеку задач явной обработке потоков, поскольку она более оптимизирована. Также у вас есть больше функций, таких как Продолжение.

саносдоле
источник
5
Нет, это не так. Он просто запускает задачи. Это может поставить задачу в очередь в пуле потоков или выполнить ее синхронно. TPL освобождает вас от управления потоками / параллелизмом самостоятельно и использует лучшее для вашей платформы (например, использование ядер)
sanosdole
10
Есть опция TaskCreationOptions.LongRunning, которая всегда будет создавать другой поток, но все дело в том, зачем вам нужен другой поток? Если вы просто хотите делать что-то параллельно (Main делает что-то во время выполнения Task), предпочтительнее позволить оптимизированной библиотеке решать, как использовать системные ресурсы, такие как потоки, чтобы сделать это наиболее эффективным способом.
sanosdole
3
В этой статье msdn описывается, как планируются задачи. Он охватывает длительный запуск и встраивание (синхронное выполнение). msdn.microsoft.com/en-us/library/dd997402.aspx
sanosdole,
2
@sming Дело в том, что вы хотите обрабатывать одновременно (не блокируя UI), а не в том, что вам нужен новый поток. ThreadPool не будет блокировать поток пользовательского интерфейса, но будет управлять фоновыми потоками гораздо эффективнее, чем вы могли бы сделать вручную, создав потоки. Это изменение мышления, которое вносит TPL. Не думайте о потоках, думайте о параллельных задачах.
sanosdole
4
@sming Извини, это предложение было слишком грубым. Синхронное выполнение задач называется встраиванием. При планировании задачи в пуле потоков (планировщик по умолчанию) из потока пользовательского интерфейса этого не произойдет. Это произойдет, только если внешний планировщик ('TaskScheduler.Current') совпадает с планировщиком задачи, которую вы вызываете '.Wait ()'. Поскольку '.Wait ()' блокирует, он в любом случае будет блокировать пользовательский интерфейс. Кратко: не ждите вызова и он не будет выполняться синхронно.
sanosdole
74

Задача дает вам все возможности API задачи:

  • Добавление продолжений ( Task.ContinueWith)
  • Ожидание выполнения нескольких задач (всех или любых)
  • Выявление ошибок в задаче и их последующий анализ
  • Захват отмены (и позволяющий указать отмену для начала)
  • Возможное возвращаемое значение
  • Использование await в C # 5
  • Лучший контроль над планированием (если оно будет долгим, скажите об этом при создании задачи, чтобы планировщик задач мог это учесть)

Обратите внимание, что в обоих случаях вы можете немного упростить свой код с помощью преобразований групп методов:

DataInThread = new Thread(ThreadProcedure);
// Or...
Task t = Task.Factory.StartNew(ThreadProcedure);
Джон Скит
источник
8
+1. Я хотел бы добавить, что Threadэто очень низкий уровень по сравнению с Task(у меня есть сообщение в блоге , в котором подробно рассказывается). На Grand Rapids DevDay я выступаю с лекцией «Использование задач в реальном мире» . Обсуждение называется «Поток мертв», потому что в нем больше нет необходимости Thread(если вы не реализуете a TaskScheduler).
Стивен Клири
@StephenCleary, я предполагаю, что вы имеете в виду, что Threadон мертв, когда дело доходит до использования в качестве фонового потока?
ebb
1
@ebb: Нет, я занимаю более сильную позицию, описанную в моем первом комментарии. Нет ничего, что Threadможно сделать (или BackgroundWorker) сделать более элегантным Taskи подходящим TaskScheduler.
Стивен Клири
1
@StephenCleary, как бы вы создали выделенную ветку без использования Thread?
ebb
4
@ebb: Мне непонятна "выделенная тема". Если вы хотите Taskработать на определенную тему, а затем использовать соответствующий TaskScheduler- например, AsyncContextThread. Однако обычно в этом нет необходимости; SynchronizationContext, ThreadPoolи ConcurrentExclusiveSchedulerPairпланировщики достаточно для большинства программ.
Стивен Клири
12

В первом случае вы просто запускаете новый поток, а во втором - входите в пул потоков.

Задача пула потоков - разделять и повторно использовать потоки. Это позволяет избежать потери нескольких миллисекунд каждый раз, когда нам нужно создать новый поток.

Есть несколько способов войти в пул потоков:

  • с TPL (параллельная библиотека задач), как вы
  • вызывая ThreadPool.QueueUserWorkItem
  • путем вызова BeginInvoke для делегата
  • когда вы используете BackgroundWorker
александреков
источник
1

Ваш первый блок кода сообщает CLR создать для вас поток (скажем, T), который можно запустить в фоновом режиме (используйте потоки пула потоков при планировании T). Короче говоря, вы явно просите CLR создать поток, чтобы вы что-то сделали, и вызывали метод Start () в потоке для запуска.

Ваш второй блок кода делает то же самое, но делегирует (неявно передает) ответственность за создание потока (фоновый, который снова запускается в пуле потоков) и начальный поток через метод StartNew в реализации фабрики задач.

Это быстрое различие между данными блоками кода. Сказав это, есть несколько подробных различий, которые вы можете найти в Google или увидеть другие ответы от моих коллег.

s_nair
источник