В чем разница между задачей и потоком? - PullRequest
350 голосов
/ 09 ноября 2010

В C # 4.0 у нас есть Task в System.Threading.Tasks пространстве имен.В чем истинная разница между Thread и Task.Я сделал несколько примеров программ (помощь взята из MSDN) для собственного изучения

Parallel.Invoke 
Parallel.For 
Parallel.ForEach 

, но у меня много сомнений, так как идея не столь ясна.

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

Ответы [ 7 ]

427 голосов
/ 09 ноября 2010

В терминах информатики, Task - это будущее или обещание . (Некоторые люди используют эти два термина синонимно, некоторые используют их по-разному, никто не может согласиться с точным определением.) По сути, Task<T> "обещает" вернуть вам T, но не сейчас дорогая, я немного занята, почему бы тебе не вернуться позже?

A Thread - это способ выполнить это обещание. Но не каждому Task нужен новый Thread. (На самом деле, создание потока часто нежелательно, потому что это намного дороже, чем повторное использование существующего потока из пула потоков. Об этом чуть позже.) Если ожидаемое вами значение приходит из файловой системы или базы данных или сети, то нет необходимости для потока сидеть и ждать данных, когда он может обслуживать другие запросы. Вместо этого Task может зарегистрировать обратный вызов для получения значений, когда они будут готовы.

В частности, Task не не говорит , почему так много времени занимает возвращение значения. Возможно, , что для вычисления потребуется много времени, или для извлечения потребуется много времени. Только в первом случае вы можете использовать Thread для запуска Task. (В .NET потоки чертовски дороги, поэтому вы, как правило, хотите избегать их настолько, насколько это возможно, и действительно используете их только в том случае, если вы хотите выполнять несколько тяжелых вычислений на нескольких процессорах. Например, в Windows поток весит 12 Кбайт (Я думаю), в Linux поток весит всего 4 килобайта, в Erlang / BEAM даже 400 байтов. В .NET это 1 микроб!)

293 голосов
/ 09 ноября 2010

Задача - это то, что вы хотите сделать.

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

В терминах .NET 4.0, Задача представляет асинхронную операцию. Поток (ы) используются для завершения этой операции, разбивая работу на куски и назначая отдельным потокам.

29 голосов
/ 15 июля 2017

Тема

Простая вещь, вам, вероятно, не нужно ее использовать, вы, вероятно, можете использовать задачу LongRunning и воспользоваться преимуществами TPL - Task Parallel Library, включенной в .NET Framework 4 (февраль 2002) и выше (также .NET Core).

Задачи

Абстракция над потоками. Он использует пул потоков (если вы не зададите задачу как операцию LongRunning, если это так, для вас будет создан новый поток).

Пул потоков

Как следует из названия: пул потоков. .NET Framework обрабатывает ограниченное количество потоков для вас. Зачем? Потому что открытие 100 потоков для выполнения дорогостоящих операций с процессором на процессоре с 8 ядрами определенно не очень хорошая идея. Фреймворк будет поддерживать этот пул для вас, повторно используя потоки (не создавая / не убивая их при каждой операции), и выполняя некоторые из них параллельно, таким образом, чтобы ваш ЦП не работал.

Хорошо, но когда использовать каждый из них?

В резюме: всегда используйте задачи.

Задача - это абстракция, поэтому ее намного проще использовать. Я советую вам всегда пытаться использовать задачи, и если вы сталкиваетесь с какой-то проблемой, которая заставляет вас обрабатывать поток самостоятельно (вероятно, в 1% случаев), то используйте потоки.

НО помните, что:

  • I / O Bound : Для операций, связанных с I / O (вызовы базы данных, чтение / запись файлов, вызовы API и т. Д.), Избегайте использования обычных задач, используйте задачи LongRunning ( или потоки). если вам нужно ). Потому что использование задач приведет вас к пулу потоков с несколькими занятыми потоками и множеством других задач, ожидающих своей очереди, чтобы занять пул.
  • CPU Bound : Для операций с CPU просто используйте обычные задачи (которые внутренне будут использовать пул потоков) и будьте счастливы.
7 голосов
/ 20 июля 2012

Вы можете использовать Task, чтобы указать, что вы хотите сделать, затем присоедините это Task к Thread.так что Task будет выполнено в только что созданном Thread, а не в потоке GUI.

Используйте Task с TaskFactory.StartNew(Action action).Здесь вы выполняете делегат, поэтому, если вы не используете какой-либо поток, он будет выполнен в том же потоке (поток GUI).Если вы упомянули поток, вы можете выполнить этот Task в другом потоке.Это ненужная работа, поскольку вы можете напрямую выполнить делегат или присоединить этот делегат к потоку и выполнить этот делегат в этом потоке.Так что не используйте это.это просто ненужно.Если вы намерены оптимизировать свое программное обеспечение, это хороший кандидат на удаление.

** Обратите внимание, что Action является delegate.

6 голосов
/ 02 августа 2017

В дополнение к вышеперечисленным пунктам было бы полезно знать, что:

  1. Задача по умолчанию является фоновой задачей. Вы не можете иметь задачу переднего плана. С другой стороны, поток может быть фоновым или передним (используйте свойство IsBackground, чтобы изменить поведение).
  2. Задачи, созданные в пуле потоков, перерабатывают потоки, что помогает экономить ресурсы. Поэтому в большинстве случаев задачи должны быть вашим выбором по умолчанию.
  3. Если операции выполняются быстро, лучше использовать задачу вместо потока. Для длительных операций задачи не дают больших преимуществ перед потоками.
2 голосов
/ 22 июля 2018

Я обычно использую Task для взаимодействия с Winforms и простым фоновым рабочим, чтобы он не зависал. вот пример, когда я предпочитаю использовать Task

private async void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    await Task.Run(() => {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
    })
    buttonDownload.Enabled = true;
}

VS

private void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    Thread t = new Thread(() =>
    {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
        this.Invoke((MethodInvoker)delegate()
        {
            buttonDownload.Enabled = true;
        });
    });
    t.IsBackground = true;
    t.Start();
}

разница в том, что вам не нужно использовать MethodInvoker и более короткий код.

2 голосов
/ 27 марта 2017

Задача похожа на операцию, которую вы хотите выполнить, Thread помогает управлять этой операцией через несколько узлов процесса. Задача - это легкий вариант, так как многопоточность может привести к сложному управлению кодом
Я предлагаю читать из MSDN (Лучший в мире) всегда

Задание

Тема

...