使用异步和等待关键字的好处
我是在C#中使用异步方法的新手。 我已经读过这些关键字async
并await
帮助,通过不同步某些方法来提高程序的响应速度。 我有这个片段:
第一条路
public static void Main()
{
Console.WriteLine("Hello!! welcome to task application");
Console.ReadKey();
Task<string> ourtask = Task.Factory.StartNew<string>(() =>
{
return "Good Job";
});
ourtask.Wait();
Console.WriteLine(ourtask.Result);
Console.ReadKey();
}
第二条路
public static void Main()
{
Launch();
}
public static async void Launch()
{
Console.WriteLine("Hello!! welcome to task application");
Console.ReadKey();
Console.WriteLine(await GetMessage());
Console.ReadKey();
}
public static Task<string> GetMessage()
{
return Task.Factory.StartNew<string>(() =>
{
return "Good Job";
});
}
我需要知道 :
这两种实现(在并行性概念中)有区别吗?
如果我可以创建一个任务并等待它完成,那么使用async
和await
关键字有什么好处?
假设你有一个单一的边界检查点。 每辆车都可以一个接一个地通过,让海关人员看看他们的车,看看他们是不是走私任何比利时巧克力。
现在假设你在你的大众甲壳虫中排队,在那里你几乎无法适应,并且在你是24轮monstertruck之前。 你现在被困在这个庞然大物之前很长一段时间,直到海关完成搜寻,然后才能转移到你身上,他们基本上只需要拍下来告诉你你很好。
为了对抗这种效率,我们在边防巡逻队的好朋友有一个想法,并安装了第二个检查站。 现在他们可以通过两倍的人,你可以拿走那一个,而不是等待monstertruck!
问题解决了,对吧? 不完全是。 他们忘了创建第二条通往检查站的道路,所以所有的车辆都必须通过单车道,导致卡车仍然挡住甲壳虫。
这与你的代码有什么关系? 非常简单:你也一样。
当你创建一个新的Task
你基本上会创建第二个检查点。 但是,如果您现在使用.Wait()
同步阻止它,则会迫使每个人都走一条路。
在第二个例子中,您使用await
创建第二条道路,并允许您的车与卡车同时处理。
我会直接回答这些问题:
你的两个例子(有效地)都不涉及任何并行性。 我看到它们之间的两个主要区别:1)第一个示例将在第二个线程上运行任务时阻塞线程,这是毫无意义的,2)第二个示例将提前退出。 遇到await
时,控制立即返回到Main()
,并且由于您并未等待从Launch()
返回的任务完成,因此您的程序将在该点退出。
使用async
和await
任务完成的好处在于, await
在任务运行时不会阻塞当前线程。 在引擎盖下,只要编译器遇到await
,它就会有效地将该方法的其余部分重写为一个将在任务完成时调用的回调。 这释放了当前线程在任务运行时执行其他操作,例如响应客户端应用程序中的用户输入或服务Web应用程序中的其他请求。
坦率地说,这不是一个很好的例子来证明async
/ await
的好处。 你基本上是说你想做CPU约束的工作,并且在工作完成之前你不想做其他事情。 你也可以做同步。 在执行I / O绑定工作时(例如在网络上进行调用(使用正确实现的异步库,例如HttpClient)),异步真的很明显,因为您不像第二个示例那样仅仅为另一个线程交易一个线程; 实际上没有线程被I / O绑定的工作所消耗。
正如其他人所暗示的,并行性完全是另一个话题。 虽然async
/ await
可能是有用的帮助你实现它的建议,但还是有更多的参与,并且在我看来,在“移动”到并行之前,你最好能够牢牢抓住脱线的好处。
也正如其他人所暗示的那样,这是一个很大的话题,我强烈建议您查看一些优秀的资源。 由于我已经引用了Stephen Cleary的博客,因此我会继续给它一个完整的插件 - 他的异步/等待介绍,随后的帖子是关于这个主题的优秀入门。
异步/等待清理了大量复杂的代码,这些代码将过度利用Task.ContinueWith.ContinueWith.ContinueWith等。
从编码的角度来看,更难以可视化,调试和维护Task.ContinueWith,包括必须随附的相关异常处理。
所以, 等待来了,并给了我们这个
public static void Main()
{
Launch();
}
public static async void Launch()
{
Console.WriteLine("Hello!! welcome to task application");
Console.ReadKey();
Console.WriteLine(await GetMessage());
Console.ReadKey();
}
public static Task<string> GetMessage()
{
return Task.Factory.StartNew<string>(() =>
{
return "Good Job";
});
}
这几乎等同于:
public static void Main()
{
Launch();
}
public static async void Launch()
{
Console.WriteLine("Hello!! welcome to task application");
Console.ReadKey();
return Task.Factory.StartNew(() => GetMessage())
.ContinueWith((t) =>
{
Console.WriteLine(t.Result)
Console.ReadKey();
});
}
public static Task<string> GetMessage()
{
return Task.Factory.StartNew<string>(() =>
{
return "Good Job";
});
}
您可以从示例中看出,GetMessage()后面的所有内容都包含在ContinueWith中,但该方法在创建后立即返回该任务。 所以它返回到调用方法。
在这里,我们需要等待该任务,否则程序将继续退出:
Launch().Wait();
不必编写ContinueWith()就意味着我们的代码变得更具可读性,特别是当我们必须在一个方法中链接多个await块时,它会“读取”正常。
同样如前所述,更好的异常处理是等待例子的处理,否则我们将不得不使用TPL方法来处理异常,这也会使代码库复杂化。
关于你的两个例子,它们并不完全等价,所以你不能真正判断一个。 但是, 异步/等待相当于构建任务/ ContinueWith。
我将异步/等待视为TPL向实际语言本身的演变。 一种语法糖。
链接地址: http://www.djcxy.com/p/13925.html