Task中Wait()和Result造成死锁

        在使用Task的时候,一不留神就会造成死锁,而且难以发现,尤其是业务繁多的情况下,一个Task嵌套另一个Task的时候,下面就演示一下,在什么情况下,会产生Wait()和Result的死锁,因此,我们就要避免这样的写法。

目录

一、Wait()死锁

二、Result死锁

一、Wait()死锁

首先执行下面这段代码,点击按钮的时候,界面直接就卡死了。

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            A().Wait();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task A()
        {
            await Task.Delay(1000);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
        }

如下图所示,而且运行显示的线程是1,也就是在执行A().Wait();时,程序就死了。

死去的原因就是A方法里面,要等待1s,它们都是主线程,所以到了 A().Wait()时,主线程会卡死这里,形成了互相等待的局面,你等我,我等你,就产生了死锁。

解决死锁的方式有2种。

1.只增加一句代码即可

增加.ConfigureAwait(false)

    private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            A().Wait();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task A()
        {
            await Task.Delay(1000).ConfigureAwait(false);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
        }

这句的意思就是,让你重新建立一个线程,把主线程让出去,这样就不会死锁了。

此时点击按钮,就会产生一个线程4,等线程4执行完毕后,就回到了主线程上。 

2. 增加await(推荐)

      private async void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            //A().Wait();                                                            //A().Wait();
            await A();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task A()
        {
            await Task.Delay(1000);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
        }

此时点击按钮,会看到都是同样的线程

虽然都解决了死锁,但是他们的原理是不一样的,第2种,始终都是1个主线程再执行,第1个开启了一个线程,干完事后,又回到了主线程上。

微软也建议我们async到底,一直传染下去。 

二、Result死锁

这种死锁主要是Task中,带有返回的值。

我们改造一下即可

     private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            string str = A().Result;
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task<string> A()
        {
            await Task.Delay(1000);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
            return "123";
        }

此时点击按钮,界面卡死了

解决方式和上面的一样,同样有2种方式

1.增加.ConfigureAwait(false)

    private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            string str = A().Result;
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task<string> A()
        {
            await Task.Delay(1000).ConfigureAwait(false);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
            return "123";
        }

点击按钮后,界面就不会卡了,也是创建了一个线程,完成后,回到主线程上面 

2.增加await(推荐)

     private async void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            string str =await A();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task<string> A()
        {
            await Task.Delay(1000);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
            return "123";
        }

此时点击按钮,界面不卡了,会看到都是同样的线程,和上面的一模一样。

拓展

当我们基于第二部分的第2种方法,加上了.ConfigureAwait(false)

将会有什么变化呢?

代码:

    private async void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            string str =await A();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task<string> A()
        {
            await Task.Delay(1000).ConfigureAwait(false);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
            return "123";
        }

效果 

界面也不卡了,但是发现到,界面还是开启了一个线程,然后回到主线程上,虽然他们的功能都是一样的,但是这种方法肯定不如单个主线程好,因为开启一个线程,也需要耗费资源。 

所以,ConfigureAwait(false)这句代码非常的重要,界面是否卡死,就是他的原因,意思就是是否立即返回主线程干活,true是,false否。

当我们改成true,又是单个主线程执行了,此时,其实ConfigureAwait(true)是句无效的代码,因为就算你返回了,那边还有一句await,await主线程,都是在一个线程上。

来源:

Task中Wait()和Result造成死锁-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/213140.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java系类 之 String、StringBuffer和StringBuilder类的区别

我 | 在这里 &#x1f575;️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 &#x1f3e0; 工作 | 广州 ⭐ Java 全栈开发&#xff08;软件工程师&#xff09; &#x1f383; 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 ✈️已经旅游的地点 | 新疆-乌鲁木齐、新疆-吐鲁番、广东-广州…

07、基于LunarLander登陆器的强化学习案例(含PYTHON工程)

07、基于LunarLander登陆器的强化学习&#xff08;含PYTHON工程&#xff09; 开始学习机器学习啦&#xff0c;已经把吴恩达的课全部刷完了&#xff0c;现在开始熟悉一下复现代码。全部工程可从最上方链接下载。 基于TENSORFLOW2.10 0、实践背景 gym的LunarLander是一个用于…

【论文 | 联邦学习】 | Towards Personalized Federated Learning 走向个性化的联邦学习

Towards Personalized Federated Learning 标题&#xff1a;Towards Personalized Federated Learning 收录于&#xff1a;IEEE Transactions on Neural Networks and Learning Systems (Mar 28, 2022) 作者单位&#xff1a;NTU&#xff0c;Alibaba Group&#xff0c;SDU&…

【设计模式-4.1】行为型——观察者模式

说明&#xff1a;本文介绍设计模式中行为型设计模式中的&#xff0c;观察者模式&#xff1b; 商家与顾客 观察者模式属于行为型设计模式&#xff0c;关注对象的行为。以商家与顾客为例&#xff0c;商家有商品&#xff0c;顾客来购买商品&#xff0c;如果商家商品卖完了&#…

go语言学习-并发编程(并发并行、线程协程、通道channel)

1、 概念 1.1 并发和并行 并发:具有处理多个任务的能力 (是一个处理器在处理任务)&#xff0c;cpu处理不同的任务会有时间错位&#xff0c;比如有A B 两个任务&#xff0c;某一时间段内在处理A任务&#xff0c;这时A任务需要停止运行一段时间&#xff0c;那么会切换到处理B任…

DockerFile常用保留字指令及知识点合集

目录 DockerFile加深理解&#xff1a; DockerFile常用保留字指令 保留字&#xff1a; RUN&#xff1a;容器构建时需要运行的命令 COPY&#xff1a;类似ADD&#xff0c;拷贝文件和目录到镜像中。 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 …

【动态规划】LeetCode-面试题 17.16. 按摩师

&#x1f388;算法那些事专栏说明&#xff1a;这是一个记录刷题日常的专栏&#xff0c;每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目&#xff0c;在这立下Flag&#x1f6a9; &#x1f3e0;个人主页&#xff1a;Jammingpro &#x1f4d5;专栏链接&…

vs 安装 qt qt扩展

1 安装qt 社区版 免费 Download Qt OSS: Get Qt Online Installer 2 vs安装 qt vs tools 3 vs添加 qt添加 bin/cmake.exe 路径 3.1 扩展 -> qt versions 3.2

【STM32】STM32学习笔记-新建工程(04)

00. 目录 文章目录 00. 目录01. 创建STM32工程02. STM32工程编译和下载03. LED测试04. 型号分类及缩写05. 工程结构06. 附录 01. 创建STM32工程 【STM32】STM32F103C8T6 创建工程模版详解(固件库) 02. STM32工程编译和下载 2.1 选择下载器位ST-Link Debugger 2.2 勾选上电…

04. 函数

目录 1、前言 2、Python中的函数 2.1、内置函数 2.2、自定义函数 2.3、函数调用 3、函数的参数 3.1、形参和实参 3.2、位置参数&#xff08;Positional Arguments&#xff09; 3.3、默认参数&#xff08;Default Arguments&#xff09;&#xff1a; 3.4、关键字参数&a…

如何为C#WinFrom编译的.exe添加个性化图标

1、在VS中点击菜单栏上的“项目”,找到最下面的属性&#xff0c;单击进去 2、加载自定义的.ico文件&#xff0c;如果没有此格式的文件可以使用此网站去转换&#xff1a;图标制作大师 - 轻松制作网站favicon图标 3、重新编译文件即可

【【水 MicroBlaze 最后的介绍和使用】】

水 MicroBlaze 最后的介绍和使用 我对MicroBlaze 已经有了一个普遍的理解 了 现在我将看的两个 一个是 AXI4接口的 DDR读写实验 还有一个是 AXI DMA 环路实验 虽然是 水文 但是 也许能从中 得到一些收获 第一个是 AXI DDR 读写实验 Xilinx 从 Spartan-6 和 Virtex-6 系列开始…

SSM框架(六):SpringBoot技术及整合SSM

文章目录 一、概述1.1 简介1.2 起步依赖1.3 入门案例1.4 快速启动 二、基础配置2.1 三种配置文件方式2.2 yaml文件格式2.3 yaml读取数据方式&#xff08;3种&#xff09; 三、多环境开发3.1 yml文件-多环境开发3.2 properties文件-多环境开发3.3 多环境命令行启动参数设置3.4 多…

【数值计算方法(黄明游)】函数插值与曲线拟合(一):Lagrange插值【理论到程序】

​ 文章目录 一、近似表达方式1. 插值&#xff08;Interpolation&#xff09;2. 拟合&#xff08;Fitting&#xff09;3. 投影&#xff08;Projection&#xff09; 二、Lagrange插值1. 天书1. 人话拉格朗日插值方法a. 线性插值&#xff08;n1&#xff09;基本思想线性插值与线…

解决uview中uni-popup弹出层不能设置高度问题

开发场景&#xff1a;点击条件筛选按钮&#xff0c;在弹出的popup框中让用户选择条件进行筛选 但是在iphone12/13pro展示是正常&#xff0c;但是切换至其他手机型号就填充满了整个屏幕&#xff0c;需要给这个弹窗设置一个固定的高度 iphone12/13pro与其他型号手机对比 一开始…

智能优化算法应用:基于海洋捕食者算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于海洋捕食者算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于海洋捕食者算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.海洋捕食者算法4.实验参数设定5.算法结果…

工业机器视觉megauging(向光有光)使用说明书(四,轻量级的visionpro)

第三个相机的添加&#xff0c;突然发现需要补充一下&#xff1a; 第一步&#xff0c;假定你对c#编程懂一点&#xff0c;我们添加了一个页面“相机三”在tabcontrol1&#xff1a; 第二步&#xff0c;添加dll到工具箱&#xff1a; 第三步&#xff0c;点击‘浏览’&#xff0c;找…

Web前端JS如何获取 Video/Audio 视音频声道(左右声道|多声道)、视音频轨道、音频流数据

写在前面&#xff1a; 根据Web项目开发需求&#xff0c;需要在H5页面中&#xff0c;通过点击视频列表页中的任意视频进入视频详情页&#xff0c;然后根据视频的链接地址&#xff0c;主要是 .mp4 文件格式&#xff0c;在进行播放时实时的显示该视频的音频轨道情况&#xff0c;并…

Fiddler抓包工具之Fiddler+willow插件应用

安装Fiddler的安装包地址&#xff1a;fillderwillow 解压后安装fiddler4和willow1.4.*版本。 安装成功后&#xff0c;启动fiddler后会出现willow插件按钮&#xff1a; 说明安装成功。 重定向 willow重定向 进入willow界面后&#xff0c;通过右键->Add Project ->Add Ru…

canvas基础:fillStyle 和strokeStyle示例

canvas实例应用100 专栏提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。 canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重要的帮助。 文章目录 上色…