В чем разница между Task.Start / Wait и Async / Await? - PullRequest
200 голосов
/ 01 марта 2012

Я могу что-то упустить, но в чем разница между:

public void MyMethod()
{
  Task t = Task.Factory.StartNew(DoSomethingThatTakesTime);
  t.Wait();
  UpdateLabelToSayItsComplete();
}

public async void MyMethod()
{
  var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
  await result;
  UpdateLabelToSayItsComplete();
}

private void DoSomethingThatTakesTime()
{
  Thread.Sleep(10000);
}

Ответы [ 6 ]

383 голосов
/ 01 марта 2012

Я могу что-то упустить

Вы.

В чем разница между Task.Wait и await task?

Вы заказываете обед у официанта в ресторане. Через мгновение после заказа ваш друг входит и садится рядом с вами и начинает разговор. Теперь у вас есть два варианта. Вы можете игнорировать своего друга, пока задача не будет завершена - вы можете ждать, пока прибудет ваш суп, и больше ничего не делать, пока вы ждете. Или вы можете ответить своему другу, и когда ваш друг перестанет говорить, официант принесет вам ваш суп.

Task.Wait блокируется, пока задача не будет завершена - вы игнорируете своего друга, пока задача не будет завершена. await продолжает обрабатывать сообщения в очереди сообщений, а когда задача завершается, она помещает в очередь сообщение, в котором говорится: «Поднимите, где вы остановились после этого ожидания». Вы разговариваете со своим другом, и когда в перерыве происходит перерыв, прибывает суп.

116 голосов
/ 01 марта 2012

Чтобы продемонстрировать ответ Эрика, вот код:

public void ButtonClick(object sender, EventArgs e)
{
  Task t = new Task.Factory.StartNew(DoSomethingThatTakesTime);
  t.Wait();  
  //If you press Button2 now you won't see anything in the console 
  //until this task is complete and then the label will be updated!
  UpdateLabelToSayItsComplete();
}

public async void ButtonClick(object sender, EventArgs e)
{
  var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
  await result;
  //If you press Button2 now you will see stuff in the console and 
  //when the long method returns it will update the label!
  UpdateLabelToSayItsComplete();
}

public void Button_2_Click(object sender, EventArgs e)
{
  Console.WriteLine("Button 2 Clicked");
}

private void DoSomethingThatTakesTime()
{
  Thread.Sleep(10000);
}
44 голосов
/ 29 сентября 2015

Этот пример очень четко демонстрирует разницу.При использовании async / await вызывающий поток не будет блокировать и продолжать выполнение.

static void Main(string[] args)
{
    WriteOutput("Program Begin");
    // DoAsTask();
    DoAsAsync();
    WriteOutput("Program End");
    Console.ReadLine();
}

static void DoAsTask()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
    WriteOutput("2 - Task started");
    t.Wait();
    WriteOutput("3 - Task completed with result: " + t.Result);
}

static async Task DoAsAsync()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
    WriteOutput("2 - Task started");
    var result = await t;
    WriteOutput("3 - Task completed with result: " + result);
}

static int DoSomethingThatTakesTime()
{
    WriteOutput("A - Started something");
    Thread.Sleep(1000);
    WriteOutput("B - Completed something");
    return 123;
}

static void WriteOutput(string message)
{
    Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, message);
}

Выход DoAsTask:

[1] Program Begin
[1] 1 - Starting
[1] 2 - Task started
[3] A - Started something
[3] B - Completed something
[1] 3 - Task completed with result: 123
[1] Program End

Выход DoAsAsync:

[1] Program Begin
[1] 1 - Starting
[1] 2 - Task started
[3] A - Started something
[1] Program End
[3] B - Completed something
[3] 3 - Task completed with result: 123

Обновление: улучшенный пример, показывающий идентификатор потока в выводе.

9 голосов
/ 27 февраля 2017

Wait (), приведет к запуску потенциально асинхронного кода в режиме синхронизации.await не будет.

Например, у вас есть веб-приложение asp.net.UserA вызывает / getUser / 1 конечную точку.Пул приложений asp.net выберет поток из пула потоков (Thread1), и этот поток выполнит HTTP-вызов.Если вы сделаете Wait (), этот поток будет заблокирован, пока не разрешится вызов http.Пока он ожидает, если UserB вызывает / getUser / 2, тогда пулу приложений потребуется обслуживать другой поток (Thread2) для повторного вызова http.Вы только что создали (ну, на самом деле, извлекли из пула приложений) другой поток без какой-либо причины, потому что вы не можете использовать Thread1, поскольку он был заблокирован функцией Wait ().

Если вы используете await в Thread1, то SyncContext будет управлять синхронизацией.между потоком 1 и вызовом http.Просто он будет уведомлять, как только http-вызов завершен.Между тем, если UserB вызывает / getUser / 2, то вы снова будете использовать Thread1 для выполнения http-вызова, потому что он был освобожден после того, как ожидают попадания.Тогда другой запрос может использовать его, даже дальше.После завершения http-вызова (user1 или user2) Thread1 может получить результат и вернуться к вызывающей стороне (клиенту).Тема 1 использовалась для нескольких задач.

8 голосов
/ 01 марта 2012

В этом примере не так много, практически.Если вы ожидаете Задачу, которая возвращается в другой поток (например, вызов WCF) или передает управление операционной системе (например, File IO), await будет использовать меньше системных ресурсов, не блокируя поток.

3 голосов
/ 01 сентября 2017

В приведенном выше примере вы можете использовать «TaskCreationOptions.HideScheduler» и значительно изменить метод «DoAsTask». Сам метод не является асинхронным, как это происходит с «DoAsAsync», потому что он возвращает значение «Задача» и помечается как «асинхронный», создавая несколько комбинаций, и это дает мне то же самое, что и использование «async / await» :

static Task DoAsTask()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime, TaskCreationOptions.HideScheduler); //<-- HideScheduler do the magic

    TaskCompletionSource<int> tsc = new TaskCompletionSource<int>();
    t.ContinueWith(tsk => tsc.TrySetResult(tsk.Result)); //<-- Set the result to the created Task

    WriteOutput("2 - Task started");

    tsc.Task.ContinueWith(tsk => WriteOutput("3 - Task completed with result: " + tsk.Result)); //<-- Complete the Task
    return tsc.Task;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...