Задача против различий потоков [дубликат]



этот вопрос уже есть ответ здесь:




  • В чем разница между задачей и нить?

    8 ответов



Я новичок в параллельном программировании. В .NET доступны два класса:Task и Thread.



Итак, вопрос: в чем разница между этими классами? Когда лучше использовать Thread и когда Task?

743   4  

4 ответов:

Thread Это концепция более низкого уровня: если вы непосредственно запускаете поток, вы знаю это будет отдельный поток, а не выполнения в пуле потоков и т. д.

Task это больше, чем просто абстракция "где запустить какой - то код", хотя-это действительно просто "обещание результата в будущем". Так же несколько разных примеров:

  • Task.Delay не нужно никакого фактического времени процессора; это так же, как установка таймера, чтобы уйти в будущее
  • задача, возвращаемая WebClient.DownloadStringTaskAsync не займет много времени процессора локально; это представляет собой результат, который, вероятно, проведет большую часть своего времени в сети задержки или удаленной работы (на веб-сервере)
  • задача, возвращаемая Task.Run() действительно и говоря "я хочу, чтобы вы выполнили этот код отдельно"; точный поток, на котором выполняется этот код, зависит от ряда факторов.

отметим, что Task<T> абстракция имеет решающее значение для асинхронного поддержка в C# 5.

в общем, я бы рекомендовал вам использовать абстракцию более высокого уровня везде, где вы можете: в современном коде C# вам редко нужно явно запускать свой собственный поток.

источник

Thread

поток представляет собой фактический поток уровня ОС, со своими собственными ресурсами стека и ядра. (технически реализация среды CLR может использовать волокна вместо этого, но ни одна существующая среда CLR не делает этого) поток позволяет самую высокую степень управления; вы можете прервать() или приостановить() или возобновить() поток (хотя это очень плохая идея), вы можете наблюдать его состояние, и вы можете установить свойства уровня потока, такие как размер стека, квартира государство или культура.

проблема с потоком заключается в том, что потоки ОС являются дорогостоящими. Каждый поток, который у вас есть, потребляет нетривиальный объем памяти для своего стека и добавляет дополнительную нагрузку на процессор в качестве контекстного переключения процессора между потоками. Вместо этого, лучше иметь небольшой пул потоков исполнения кода, так как работа становится доступной.

бывают случаи, когда нет альтернативного потока. Если вам нужно указать имя (для целей отладки) или состояние квартиры (чтобы показать пользовательский интерфейс), вы должны создать свой собственный поток (обратите внимание, что наличие нескольких потоков пользовательского интерфейса, как правило, плохая идея). Кроме того, если вы хотите поддерживать объект, который принадлежит одному потоку и может использоваться только этим потоком, гораздо проще явно создать экземпляр потока для него, чтобы вы могли легко проверить, работает ли код, пытающийся его использовать, в правильном потоке.

ThreadPool

ThreadPool-это оболочка вокруг пула потоков, поддерживаемых сброс. ThreadPool не дает вам никакого контроля вообще; вы можете отправить работу для выполнения в какой-то момент, и вы можете контролировать размер пула, но вы не можете установить ничего другого. Вы даже не можете сказать, когда пул начнет выполнять работу, которую вы ему отправляете.

использование ThreadPool позволяет избежать накладных расходов на создание слишком большого количества потоков. Однако если вы отправляете слишком много длительных задач в пул потоков, он может быть заполнен, а более поздняя работа, которую вы отправляете, может в конечном итоге ожидать более раннего длительные элементы для завершения. Кроме того, ThreadPool не предлагает способа узнать, когда рабочий элемент был завершен (в отличие от Thread.Join ()), ни способ получить результат. Поэтому ThreadPool лучше всего использовать для коротких операций, где вызывающий объект не нуждается в результате.

задание

наконец, класс задач из параллельной библиотеки задач предлагает лучшее из обоих миров. Как и ThreadPool, задача не создает свой собственный поток ОС. Вместо этого, задачи выполняется TaskScheduler; планировщик по умолчанию просто запускается в пуле потоков.

В отличие от ThreadPool, Task также позволяет узнать, когда он заканчивается, и (через общую задачу) вернуть результат. Вы можете вызвать ContinueWith() для существующей задачи, чтобы она выполняла больше кода после завершения задачи (если она уже завершена, она немедленно выполнит обратный вызов). Если задача является универсальной, ContinueWith () передаст вам результат задачи, что позволит вам запустить больше кода, который использует оно.

вы также можете синхронно дождаться завершения задачи, вызвав Wait () (или, для общей задачи, получив свойство Result). Как Нить.Join (), это заблокирует вызывающий поток до завершения задачи. Синхронное ожидание задачи обычно является плохой идеей; это предотвращает выполнение вызывающим потоком любой другой работы, а также может привести к взаимоблокировкам, если задача заканчивается ожиданием (даже асинхронно) для текущего потока.

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

все новые API параллелизма высокого уровня, включая параллель.Для методов* (), PLINQ, C# 5 await и современные асинхронные методы в BCL все построены на Задача.

вывод

суть в том, что задача почти всегда является лучшим вариантом; она обеспечивает гораздо более мощный API и позволяет избежать потери потоков ОС.

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

задача-это концепция более высокого уровня, чем поток... и вот что означает эта фраза :

  1. вы не можете использовать Abort / ThreadAbortedException, вы должны поддерживать отменить событие в вашем" бизнес-коде " периодически проверяя token.IsCancellationRequested флаг (также избегайте длинных или безвременных соединений, например, с БД, иначе вы никогда не получите возможность проверить этот флаг). По аналогичной причине Thread.Sleep(delay) следует заменить на Task.Delay(delay, token);

  2. там не являются ли функциональные возможности методов Suspend() и Resume() потока с задачами. Экземпляр задачи также не может быть использован повторно.

  3. но вы получаете два новых инструмента:продолжения, и вложенные/дочерние задачи; эти два примера демонстрируют идею и синтаксис:

      // continuation - execute the delegate, when all tasks[] had been finished
    Task.Factory.ContinueWhenAll(
    tasks,
    () =>
       {
           int answer = tasks[0].Result + tasks[1].Result;
           Console.WriteLine("The answer is {0}", answer);
       }
    );
    
    
    //StartNew - starts task immediately, parent ends whith child
    var parent = Task.Factory.StartNew
    (() => {
              var child = Task.Factory.StartNew(() =>
             {
             //...
             });
          },  
          TaskCreationOptions.AttachedToParent
    );
    
  4. таким образом, системный поток полностью скрыт от задачи, но все же код задачи выполняется в конкретном системном потоке. Система потоки-это ресурсы для задач, и, конечно же, есть пул потоков под капотом параллельного выполнения задач. Там могут быть различные стратегии, как поток получить новые задачи для выполнения. Еще один общий ресурс TaskScheduler заботится о нем. Некоторые проблемы, которые TaskScheduler решает 1) предпочитают выполнять задачу и ее conitnuation в том же потоке минимизации затрат на коммутацию-ака встроенные исполнение) 2) предпочитаю выполнять задачи в порядке их начал - ака PreferFairness 3) более эффективное распределение задач между неактивными потоками в зависимости от "предварительного знания деятельности задач" - aka Работа Краже. Важно: в целом "асинхронность" - это не то же самое, что"параллель". Играя с опциями TaskScheduler вы можете настроить асинхронные задачи, которые будут выполняться в одном потоке синхронно.

  5. задачи интегрированы с функциями c# async / await aka Обещать Модель, электронной.г есть requestButton.Clicked += async (o, e) => ProcessResponce(await client.RequestAsync(e.ResourceName)); исполнение client.RequestAsync не будет блокировать поток пользовательского интерфейса. Важно: под капотом Clicked вызов делегата является абсолютно регулярным (все потоки выполняются компилятором).

этого достаточно, чтобы сделать выбор. Если вам нужно поддерживать функцию отмены вызова устаревшего API, который имеет тенденцию зависать (например, sime timeoutless connection) и в этом случае поддерживает поток.Прервать (), или если вы создаете многопоточные фоновые вычисления и хотите оптимизировать переключение между потоками используя Suspend / Resume, это означает управлять параллельным выполнением вручную-оставаться с потоком. В противном случае перейти к задачам, потому что они дадут вам легко манипулировать на группы из них и интегрированы в язык.

The Thread класс используется для создания и работы с thread в Windows.

A Task представляет некоторую асинхронную операцию и является частью Параллельных Задач Библиотека, набор API для выполнения задач асинхронно и параллельно.

в старые времена (т. е. до TPL) это было то, что с помощью Thread класс был одним из стандартных способов выполнения кода в фоновом режиме или параллельно (а лучше часто использовать ThreadPool), однако это было громоздко и имело несколько недостатков, не последним из которых были накладные расходы на создание целого нового потока для выполнения задачи в фоновом режиме.

В настоящее время использование задач и TPL является гораздо лучшим решением 90% времени, поскольку оно обеспечивает абстракции, которые позволяют гораздо более эффективно использовать системные ресурсы. Я предполагаю, что есть несколько сценариев, где вы хотите явный контроль над поток, на котором вы запускаете свой код, однако, вообще говоря, если вы хотите запустить что-то асинхронно, ваш первый порт вызова должен быть TPL.

Comments

    Ничего не найдено.