我可能会遗漏一些东西但是做什么之间的区别是:
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);
}
答案 0 :(得分:383)
我可能遗漏了一些东西
你是。
执行
Task.Wait
和await task
之间的区别是什么?
您从餐厅的服务员那里订购午餐。在给出订单后的一刻,一位朋友走进来,坐在你身边,开始交谈。现在你有两个选择。你可以忽略你的朋友,直到任务完成 - 你可以等到你的汤到来,在你等待的时候什么都不做。或者你可以回复你的朋友,当你的朋友停止说话时,服务员会给你带来你的汤。
Task.Wait
阻止任务完成 - 在任务完成之前,您将忽略您的朋友。 await
继续处理消息队列中的消息,并且当任务完成时,它会将一条消息标记为“在等待之后从中断处继续”。你跟你的朋友说话,当谈话休息时,汤就到了。
答案 1 :(得分:116)
为了证明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);
}
答案 2 :(得分:43)
此示例非常清楚地说明了这一区别。使用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
更新:通过在输出中显示线程ID来改进示例。
答案 3 :(得分:9)
Wait(),将导致以同步方式运行潜在的异步代码。等待不会。
例如,您有一个asp.net Web应用程序。 UserA调用/ getUser / 1端点。 asp.net app pool将从线程池(Thread1)中选择一个线程,并且该线程将进行http调用。如果你执行Wait(),这个线程将被阻塞,直到http调用解析。在等待时,如果UserB调用/ getUser / 2,那么app pool将需要服务另一个线程(Thread2)再次进行http调用。你刚刚创建了(好吧,实际从app pool中获取)另一个线程,因为你无法使用Thread1它被Wait()阻止了。
如果在Thread1上使用await,则SyncContext将管理Thread1和http调用之间的同步。简单地说,一旦http呼叫完成,它将通知。同时,如果UserB调用/ getUser / 2,那么,你将再次使用Thread1进行http调用,因为它一旦被等待就被释放了。然后另一个请求可以使用它,甚至更多。一旦http调用完成(user1或user2),Thread1就可以获得结果并返回调用者(客户端)。 Thread1用于多个任务。
答案 4 :(得分:8)
在这个例子中,实际上并不多。如果您正在等待在不同线程上返回的任务(如WCF调用)或放弃对操作系统的控制(如文件IO),则await将通过不阻塞线程来使用较少的系统资源。
答案 5 :(得分:3)
在上面的示例中,您可以使用&#34; TaskCreationOptions.HideScheduler&#34;,并大大修改&#34; DoAsTask&#34;方法。该方法本身不是异步的,因为它发生在&#34; DoAsAsync&#34;因为它返回了一个&#34;任务&#34;值并标记为&#34; async&#34;,进行多种组合,这就是它与使用&#34; async / await&#34;完全相同的方式:
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;
}