217

我可能遗漏了一些东西,但是做这件事有什么区别:

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);
}
4

6 回答 6

413

我可能遗漏了一些东西

你是。

Task.Wait和 和有什么不一样await task

您从餐厅的服务员那里订购午餐。在您下订单后不久,一位朋友走进来并坐在您旁边并开始交谈。现在你有两个选择。你可以忽略你的朋友,直到任务完成——你可以等到汤上来,在等待的时候什么也不做。或者你可以回应你的朋友,当你的朋友停止说话时,服务员会给你端上你的汤。

Task.Wait阻塞直到任务完成——你忽略你的朋友,直到任务完成。await继续处理消息队列中的消息,当任务完成时,它会将一条消息排入队列,上面写着“在等待之后从你离开的地方继续”。你和你的朋友交谈,当谈话中断时,汤就来了。

于 2012-03-01T16:04:22.660 回答
124

为了演示埃里克的答案,这里有一些代码:

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);
}
于 2012-03-01T16:30:03.493 回答
54

这个例子非常清楚地说明了差异。使用 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] 节目开始
[1] 1 - 开始
[1] 2 - 任务开始
[3] A - 开始做某事
[3] B - 完成某事
[1] 3 - 任务完成,结果:123
[1] 程序结束

DoAsAsync 输出:

[1] 节目开始
[1] 1 - 开始
[1] 2 - 任务开始
[3] A - 开始做某事
[1] 程序结束
[3] B - 完成某事
[3] 3 - 任务完成,结果:123

更新:通过在输出中显示线程 ID 来改进示例。

于 2015-09-29T10:30:45.683 回答
13

Wait(),将导致以同步方式运行潜在的异步代码。await 不会。

例如,您有一个 asp.net Web 应用程序。UserA 调用 /getUser/1 端点。asp.net 应用程序池将从线程池 (Thread1) 中选择一个线程,并且该线程将进行 http 调用。如果你执行 Wait(),这个线程将被阻塞,直到 http 调用解决。在等待期间,如果 UserB 调用 /getUser/2,则应用程序池将需要服务另一个线程 (Thread2) 以再次进行 http 调用。您刚刚无缘无故地创建了(实际上是从应用程序池中获取的)另一个线程,因为您不能使用 Thread1 它被 Wait() 阻塞。

如果您在 Thread1 上使用 await,则 SyncContext 将管理 Thread1 和 http 调用之间的同步。简单地说,一旦 http 调用完成,它就会通知。同时,如果 UserB 调用 /getUser/2,那么,你将再次使用 Thread1 进行 http 调用,因为一旦 await 被命中,它就会被释放。然后另一个请求可以使用它,甚至更多。一旦 http 调用完成(user1 或 user2),Thread1 可以获取结果并返回给调用者(客户端)。Thread1 用于多个任务。

于 2017-02-27T16:26:20.117 回答
10

在这个例子中,实际上并不多。如果您正在等待在不同线程上返回的任务(如 WCF 调用)或将控制权交给操作系统(如文件 IO),则 await 将通过不阻塞线程来使用更少的系统资源。

于 2012-03-01T16:04:30.457 回答
3

在上面的例子中,可以使用“TaskCreationOptions.HideScheduler”,并对“DoAsTask”方法进行大幅度修改。该方法本身不是异步的,就像“DoAsAsync”一样,因为它返回一个“Task”值并标记为“async”,进行了多种组合,这就是它给我的方式与使用“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;
}
于 2017-08-31T23:39:03.333 回答