Winform/WPF async/await容易引起死锁的解决办法

Posted lishuangquan1987

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Winform/WPF async/await容易引起死锁的解决办法相关的知识,希望对你有一定的参考价值。

在使用Winform或者WPF编程时,无论是使用.net framework 4.x还是使用.netcore 还是使用.net5,.net6,多多少少会使用到异步方法。如果是彻彻底底的使用异步,则不会发生死锁,但是有时候我们的系统框架都是用同步写的,突然第三方库只支持异步方法,这时候调用就要小心了,可能会引起界面卡死。
如下是模拟的情况:
新建一个winform项目。界面上有个按钮。点击这个按钮,调用异步方法。
代码如下:

public partial class Form1 : Form

    public Form1()
    
        InitializeComponent();
    

    private void button1_Click(object sender, EventArgs e)
    
        var str = TestString().Result;
        MessageBox.Show(str);
    
    public async Task<string> TestString()
    
        await Task.Delay(2000);
        return "hello";
    

你会发现,这个时候,界面卡主了,会永远一直卡下去。
具体的原因分析:https://wenku.baidu.com/view/4f6ab3d49d3143323968011ca300a6c30c22f16f.html
https://blog.csdn.net/WPwalter/article/details/78370706

假定TestString这个方法是别人第三方库提供的,那我们要如何调用

解决办法一(不推荐)

异步到底。全部使用异步。如果是小的项目,改一下无所谓。大的项目,不推荐:

public partial class Form1 : Form

	   public Form1()
	   
	       InitializeComponent();
	   
	
	   private async void button1_Click(object sender, EventArgs e)
	   
	       var str =await TestString();
	       MessageBox.Show(str);
	   
	   public async Task<string> TestString()
	   
	       await Task.Delay(2000);
	       return "hello";
	   

解决方案二(推荐)

使用Task.Run包一层

public partial class Form1 : Form

    public Form1()
    
        InitializeComponent();
    

    private  void button1_Click(object sender, EventArgs e)
    
        var (ok,str) =InvokeAsyncMethod(TestString,5000);
        if (ok)
        
            MessageBox.Show(str);
        
        else
        
            MessageBox.Show("调用超时");
        
    
    public async Task<string> TestString()
    
        await Task.Delay(2000);
        return "hello";
    
    public (bool,T) InvokeAsyncMethod<T>(Func<Task<T>> func, int timeout)
    
        var result = Task.Run(async () => await func());
        if (result.Wait(timeout))
        
            return (true, result.Result);
        
        else
        
            return (false, default(T));
        
    

以上是关于Winform/WPF async/await容易引起死锁的解决办法的主要内容,如果未能解决你的问题,请参考以下文章

promise 和 async await比较

[ECMAScript] 说说你对async/await的理解?

js async await 终极异步解决方案

抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext

抓住异步编程async/await语法糖的牛鼻子

[react] 在React中怎么使用async/await?