C# await/async 程式锁死问题解析

範例程式码:

         private void button1_Click(object sender, EventArgs e)        {            Console.WriteLine($"SynchronizationContext.Current = {SynchronizationContext.Current}");            Console.WriteLine($"程式开始 执行绪ID:{Thread.CurrentThread.ManagedThreadId}");            var imng = ImageService();            Console.WriteLine($"等待ImageService结果 执行绪ID: {Thread.CurrentThread.ManagedThreadId}");            var result = imng.Result;            Console.WriteLine($"读取到的结果 : {result}");        }        private async Task<string> ImageService()        {            Console.WriteLine($"ImageService 準备开始 执行绪ID: {Thread.CurrentThread.ManagedThreadId}");            await Task.Run(() =>             {                Console.WriteLine($"Task.Run 执行绪 ID: {Thread.CurrentThread.ManagedThreadId}");                Thread.Sleep(100);                Console.WriteLine("程式已跑完");            });            Console.WriteLine($"ImageService 準备开始 执行绪ID: { Thread.CurrentThread.ManagedThreadId}");            return "程式结束";        }

输出结果

程式码

解说图

在 Windows Forms、WPF、和 ASP.NET 这类有 UI 的程式中,会使用SynchronizationContext
来存放UI执行绪的相关讯息,方便呼叫 await 叙述做完要往下继续做的时候能够切换为主执行绪继续完成任务。

如上图主执行绪 会依照程式顺序执行(a) (b)到await的时候会开一个执行续让他执行里面要等待的运算,然后主执行绪就会往下继续做,当主执行绪执行到(e)的时候他就会,等待ImageService回传的结果,所以这时候1号执行绪是忙碌中的,这时候(c)里面的程式做完了要,回来做(d)的时候,如果SynchronizationContext不是null就会由SynchronizationContext里面纪录的执行绪来完成(d)的任务,但这时 1号执行绪是忙碌的状态,要等(e)执行完才能开始做(d)的工作
因此变成(e)在等ImageService的结果,(d)在等(e)做完工作,形成了互相等的状态。

在Console不会有这情况的原因是,在Console程式中SynchronizationContext.Current=null,
所以在await完成后要往下个任务继续做的时候,会是由TaskScheduler(工作排程器)物件,来决定哪个执行绪去完成这项任务

同步发布至个人部落格:
await/async 程式锁死问题解析


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章