在.NET 4.5中,新的异步机制非常好用,但是有一点很容易搞错,那就是一旦一个await 完成了,或者说是你的一个异步任务完成了,那么接下去由谁(哪个线程上下文)来直接执行之后的代码?在Wpf中(或在Metro中),当你进行await操作后,或者使用task.GetAwaiter()返回的TaskAwaiter 对象的OnCompleted(将你想要的后续操作放入它中),那么你会发现,它们都是在UI线程中执行的(使用Thread.CurrentThread.ManagedThreadId查看,但是Metro没有Thread,但这个比照WPF就行)。代码如下:
private async void clicked(object sender, RoutedEventArgs e)
{
id0= Thread.CurrentThread.ManagedThreadId;
await Go();
}
async Task Go()
{
var task = GetAnswerToLife();
text.Text = text.Text +await task;
}
async Task<int> GetAnswerToLife()
{
var task = Task.Delay(5000);
var aw = task.GetAwaiter();
aw.OnCompleted(() =>
{
var id1 = Thread.CurrentThread.ManagedThreadId;
});
await task;
int answer = 21 * 2;
var id2=Thread.CurrentThread.ManagedThreadId;
// text.Text = text.Text +answer + "+"+id;
return answer;
}
其中clicked是一个Button的Click事件,那么我们断点每个id处,会发现id0=id1=id2。
若是在控制台应用程序中,那么结果就很不一样了,我这里就不帖代码了,把以上这段代码移到控制台应用程序上很容易。你会发现,id0和id1,id2不一样,也就是id0是主线程的id,其他的id是其他线程的id,那么即使我在每个task上加上这段代码:
task.ConfigureAwait(true);
也还是没用(注意:若ConfigureAwait为true,在UI应用中,往往让调用该task的线程回来执行task完成后的代码,往往就是UI线程,若为false,则会让执行task具体任务的工作线程来执行。所以,当你把task.ConfigureAwait(false);添加到wpf的项目里时,你会发现,id0就不等于id1和id2了)。
那具体的原因是什么呢?突然发现,要完成以上的这种可以让一个线程有空时回到await处的前提条件是,该线程应该是一个基于消息循环的应用程序,这个是由编译器来将剩余代码打包成一个消息到消息队列中,所以普通的控制台应用程序没有这种机制,也就不可能让主线程回到它去过的地方执行了。参考如下的机制:
while (!thisApplication.Ended)
{
wait for something to appear in message queue
Got something: what kind of message is it?
Keyboard/mouse message -> fire an event handler
User BeginInvoke/Invoke message -> execute delegate
}
分享到:
相关推荐
Example for binding an ObservableCollection to a ListView and using async await Task to update the data
Await 处理并行任务(WhenAll)以及Task.Delay() Await 处理并行任务(WhenAll)以及Task.Delay() Await 处理并行任务(WhenAll)以及Task.Delay() Await 处理并行任务(WhenAll)以及Task.Delay()
创建它的目的是在WPF应用程序的上下文中探索使用Serilog的潜在问题。 此应用程序使用Autofac将记录器注入MainWindow类,该类提供提供SourceContext值以记录事件。 添加了其他值以充实日志语句,但是在不同线程上...
ESRI Silverlight API 和 Runtime SDK for WPF 的 await async 扩展
当需要执行一个耗时的操作时,可以使用await关键字将该操作包裹在一个异步方法中。在操作执行期间,可以显示消息蒙版弹窗UI,并在操作完成后关闭该弹窗。 通过结合WPF的动画效果和样式设置,你可以为该消息蒙版弹窗...
最近在阅读 .NET Threadpool starvation, and how queuing makes it worse 这篇博文时发现文中代码中的一种 Task 用法之前从未见过,在网上看了一些资料后也是云里雾里不知其解,很是困扰。今天在程序员节的大好日子...
多线程的意义在于一个应用程序中,有多个执行部分可以同时执行;对于比较耗时的操作(例如io,数据库操作),或者等待响应(如WCF通信)的操作,可以单独开启后台线程来执行,这样主线程就不会阻塞,可以继续往下执行;...
小程序本身是不支持async/await语法的,但有些应用场景,我们使用async/await会使得代码更简洁,也更易于维护,用过都知道是有多爽的。既然小程序不支持,那我们可以借助 fackbook 开源的 regenerator 来完成这一...
AsyncConsoleDemo_2 System.Threading.Tasks,异步任务,Task.Run(),等待,Console.ReadKey(),Console.KeyAvailable
微信小程序中身份证信息识别源代码微信小程序中身份证信息识别源代码微信小程序中身份证信息识别源代码微信小程序中身份证信息识别源代码微信小程序中身份证信息识别源代码微信小程序中身份证信息识别源代码微信小...
以下针对ASP.NET 应用程序实际使用过程中的一些总结, 包括 异常捕获 、 死锁 、 应用程序崩溃 ,实际使用过程中一不注意就可能掉坑里了。 异常捕获 async 方法有三种返回类型: void、Task、Task async void 该方式...
1.采用background处理后台耗时程序,防止主线程阻塞,实时显示处理进度。 2.采用async_await 关键字实现异步程序编程,杜绝主线程处理耗时程序假死
同步、异步及多线程的使用(Task、Async、Await) Task线程的暂停、继续、取消 Task异步多线程调用中的死锁
为文章 Async Await 异常处理 所写,主要展示四种典型情况下的异常处理。 async await; task.wait(); async 不 await; async void
JavaScript中async,await的使用和方法 JS中 async函数和await 关键字 function hellworld() { return "您好!美好世界!"; } console.log(hellworld()); // 您好!美好世界! async function asyHellworld()...
自己写的一个winform小示例 用非常简短的几行代码演示C#5.0的异步编程新特性 不参杂其他无关代码,浅显易懂
前言 在平常的项目开发中肯定会遇到同步异步执行的问题...3.当然es6中的promise倒是很好的解决了这样的问题,再配合es7的async和await就更完美了,await返回的也是一个promise对象,这个关于promise和async,await的使
taro3.x react redux await-async promise api 能运行的工程h5/小程序
微信小程序中有大量接口是异步调用,比如 wx.login()、wx.request()、wx.getUserInfo() 等,都是使用一个对象作为参数,并定义了 success()、fail() 和 complete() 作为异步调用不同情况下的回调。 但是,以回调的...
使用Async和Await进行,异步编程,适用于vs2015平台,此案例