C# 什么';Task.Start/Wait和Async/Wait之间的区别是什么?

C# 什么';Task.Start/Wait和Async/Wait之间的区别是什么?,c#,task-parallel-library,.net-4.5,async-await,conceptual,C#,Task Parallel Library,.net 4.5,Async Await,Conceptual,我可能遗漏了一些东西,但这两者之间的区别是什么: public void MyMethod() { Task t = Task.Factory.StartNew(DoSomethingThatTakesTime); t.Wait(); UpdateLabelToSayItsComplete(); } public async void MyMethod() { var result = Task.Factory.StartNew(DoSomethingThatTakesTime

我可能遗漏了一些东西,但这两者之间的区别是什么:

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
Wait Task
之间有什么区别

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


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

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

下面是一些代码来演示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);
}

这个例子非常清楚地说明了这一区别。使用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);
}
static void Main(字符串[]args)
{
写输出(“程序开始”);
//DoAsTask();
DoAsAsync();
写输出(“程序结束”);
Console.ReadLine();
}
静态void-DoAsTask()
{
注销输出(“1-启动”);
var t=Task.Factory.StartNew(DoSomethingThatTakesTime);
写输出(“2-任务已启动”);
t、 等待();
WriteOutput(“3-任务完成,结果:+t.result”);
}
静态异步任务DoAsAsync()
{
注销输出(“1-启动”);
var t=Task.Factory.StartNew(DoSomethingThatTakesTime);
写输出(“2-任务已启动”);
var结果=等待t;
WriteOutput(“3-任务完成,结果:+结果”);
}
静态int DoSomethingThatTakesTime()
{
写输出(“A-开始某事”);
睡眠(1000);
写输出(“B-完成的某物”);
返回123;
}
静态void WriteOutput(字符串消息)
{
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 [1] 节目开始 [1] 1-启动 [1] 2-任务已启动 [3] 一开始 [3] 完成某事 [1] 3-任务已完成,结果:123 [1] 程序结束 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 [1] 节目开始 [1] 1-启动 [1] 2-任务已启动 [3] 一开始 [1] 程序结束 [3] 完成某事 [3] 3-任务已完成,结果:123 更新:通过在输出中显示线程ID改进了示例。

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

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


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

在上面的示例中,您可以使用“TaskCreationOptions.hidesScheduler”,并大大修改“DoAsTask”方法。该方法本身不是异步的,因为它返回一个“Task”值并被标记为“async”,这与使用“async/await”完全相同,所以它本身不是异步的:

静态任务DoAsTask()
{
注销输出(“1-启动”);

var t=Task.Factory.StartNew(DoSomethingThatTakesTime,TaskCreationOptions.HideScheduler);//tsc.TrySetResult(tsk.Result));//WriteOutput(“3-任务已完成,结果:+tsk.Result”))//@ronag不,不是。如果等待一个耗时10毫秒的
任务
实际上会在你的线程上执行一个10小时的
任务
,从而阻塞你整整10个小时,你会怎么想呢?@StruglingCoder:Wait操作符除了计算它的操作数,然后立即将任务返回到当前的caller.人们脑子里有这样一个想法,异步只能通过将工作转移到线程上来实现,但这是错误的。当吐司在烤面包机中时,你可以做早餐和阅读报纸,而不必雇佣厨师来观看烤面包机。人们说,烤面包机中一定隐藏着一个线程——一个工作者,但我向你保证,如果你看你的烤面包机,里面没有一个小家伙在看烤面包。@StruglingCoder:那么,谁在做你要做的工作呢?可能是另一个线程在做这项工作,而该线程已经分配给CPU,所以这项工作实际上正在完成。可能这项工作是由硬件完成的,根本没有线程。但是ely,你说,硬件中一定有线程。不。硬件存在于线程级别之下。不需要线程!你可能会从阅读Stephen Cleary的文章《没有线程》中获益。@StruglingCoder:现在,问题是,假设有异步工作
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;
}