C# Task.Start/Wait 和 Async/Await 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9519414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 07:43:04  来源:igfitidea点击:

What's the difference between Task.Start/Wait and Async/Await?

c#task-parallel-library.net-4.5async-awaitconceptual

提问by Jon

I may be missing something but what is the difference between doing:

我可能会遗漏一些东西,但这样做有什么区别:

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

采纳答案by Eric Lippert

I may be missing something

我可能错过了什么

You are.

你是。

what is the difference between doing Task.Waitand await task?

doTask.Wait和 和有await task什么不一样?

You order your lunch from the waiter at the restaurant. A moment after giving your order, a friend walks in and sits down next to you and starts a conversation. Now you have two choices. You can ignore your friend until the task is complete -- you can wait until your soup arrives and do nothing else while you are waiting. Or you can respond to your friend, and when your friend stops talking, the waiter will bring you your soup.

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

Task.Waitblocks until the task is complete -- you ignore your friend until the task is complete. awaitkeeps processing messages in the message queue, and when the task is complete, it enqueues a message that says "pick up where you left off after that await". You talk to your friend, and when there is a break in the conversation the soup arrives.

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

回答by foson

In this example, not much, practically. If you are awaiting a Task that returns on a different thread (like a WCF call) or relinquishes control to the operating system (like File IO), await will use less system resources by not blocking a thread.

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

回答by Jon

To demonstrate Eric's answer here is some code:

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

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

回答by Mas

This example demonstrates the difference very clearly. With async/await the calling thread will not block and continue executing.

这个例子非常清楚地展示了差异。使用 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 Output:

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 Output:

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

Update: Improved example by showing the thread ID in the output.

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

回答by Teoman shipahi

Wait(), will cause to run potentially async code in sync manner. await will not.

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

For example, you have an asp.net web application. UserA calls /getUser/1 endpoint. asp.net app pool will pick a thread from thread pool (Thread1) and, this thread will make a http call. If you do Wait(), this thread will be blocked until http call resolves. While it is waiting, if UserB calls /getUser/2, then, app pool will need to serve another thread (Thread2) to make http call again. You just created (Well, fetched from app pool actually) another thread for no reason, because you cannot use Thread1 it was blocked by Wait().

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

If you use await on Thread1, then, SyncContext will manage sync between Thread1 and http call. Simply, it will notify once http call is done. Meanwhile, if UserB calls /getUser/2, then, you will use Thread1 again to make http call, because it was released once await got hit. Then another request can use it, even further more. Once http call is done (user1 or user2), Thread1 can get the result and return to caller (client). Thread1 was used for multiple tasks.

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

回答by user8545699

In the example above, you can use "TaskCreationOptions.HideScheduler", and greatly modify the "DoAsTask" method. The method itself is not asynchronous, as it happens with "DoAsAsync" because it returns a "Task" value and is marked as "async", making several combinations, this is how it gives me exactly the same as using "async / await":

在上面的例子中,您可以使用“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;
}