Task.Start / Wait和Async / Await之间有什么区别?
我可能会失去一些东西,但做什么之间的区别:
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); }
我可能会错过一些东西
你是。
做
Task.Wait
和await task
什么区别?
你从餐厅的服务员那里订购午餐。 在您下订单之后的一瞬间,一位朋友走进来,坐在旁边,开始对话。 现在你有两个select。 你可以忽略你的朋友,直到任务完成 – 你可以等到你的汤到了,而你在等待的时候什么也不做。 或者你可以回应你的朋友,当你的朋友停止说话,服务员会给你带汤。
Task.Wait
阻塞,直到任务完成 – 在任务完成之前,您将忽略您的朋友。 await
在消息队列中保留处理消息,并且当任务完成时,它将排队一条消息,指出“在等待之后从哪里离开”。 你跟你的朋友聊天,当谈话中断时,汤就到了。
在这里演示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); }
这个例子非常清楚地表明了区别。 与asynchronous/等待调用线程不会阻止并继续执行。
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] - 开始了一些事情 [3] B - 完成了一些事情 [1] 3 - 任务结果:123 [1]节目结束
DoAsAsync输出:
[1]程序开始 [1] 1 - 开始 [1] 2 - 任务开始 [3] - 开始了一些事情 [1]节目结束 [3] B - 完成了一些事情 [3] 3 - 任务结果:123
更新:通过在输出中显示线程ID来改进示例。
在这个例子中,实际上并不多。 如果您正在等待在不同线程(如WCF调用)上返回的任务,或者将控制权交给操作系统(如文件IO),那么请不要通过阻塞线程来使用较less的系统资源。
Wait()会导致以同步方式运行潜在的asynchronous代码。 等待不会。
例如,你有一个asp.net web应用程序。 UserA调用/ getUser / 1端点。 asp.net应用程序池将从线程池(Thread1)中select一个线程,并且这个线程将进行http调用。 如果你做Wait(),这个线程将被阻塞,直到http呼叫parsing。 在等待时,如果UserB调用/ getUser / 2,则应用程序池将需要服务另一个线程(Thread2)再次进行http调用。 你刚刚创build(实际上从应用程序池中获取)另一个线程,因为你不能使用Thread1它被Wait()阻塞。
如果在Thread1上使用await,那么SyncContext将pipe理Thread1和http调用之间的同步。 简单地说,一旦http调用完成,它就会通知。 同时,如果UserB调用/ getUser / 2,那么您将再次使用Thread1来进行http调用,因为它一旦被释放,就会被释放。 然后另一个请求可以使用它,甚至更多。 一旦http调用完成(user1或user2),Thread1就可以得到结果并返回给调用者(客户端)。 Thread1被用于多个任务。
在上面的例子中,您可以使用“TaskCreationOptions.HideScheduler”,并大大修改“DoAsTask”方法。 这个方法本身并不是asynchronous的,就像它发生在“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; }