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