• C# 通过TaskCompletionSource解决async/await死锁的问题


    async/await 是个好东西

    但是呢,使用async/await时,很多旧项目经常会出现最外层要同步调用async/await方法的问题

    而当我们在asp.net程序和winform等具有UI线程的项目使用async/await的Result属性或者Wait()方法同步阻塞获取数据时

    就会出现死锁,具体的原因网上一搜一大把,这里就不做具体的介绍了

    大家一般通过给await函数添加.ConfigureAwait(false)来解决这个问题

    但是如果咱们引用的第三方dll内部没有这个.ConfigureAwait(false)或者其他未知问题,那就悲剧了,即使你给你所有的await都加上.ConfigureAwait(false)也依然是死锁

    这个时候就只能另想办法了,而通过TaskCompletionSource就能解决这个问题,虽然很绕,很诡异,但是至少是解决死锁了。。。

    具体的思路是创建一个TaskCompletionSource泛型对象,泛型类型为async/await返回值类型,然后开启一个新的异步线程,在这个异步线程中执行async/await方法,并将await的结果赋值给TaskCompletionSource,最后在异步线程的外面,同步阻塞调用TaskCompletionSource对象Task.Result

    这样就貌似就不会出现死锁了

    public static T Result<T>(Func<Task<T>> func) {
                var tcs = new TaskCompletionSource<T>();
                Task.Run(async () => {
                    T data = await func().ConfigureAwait(false);
                    tcs.SetResult(data);
                });
                return tcs.Task.Result;
            }
    

    具体是怎么解决的,我也不是很清楚,估计还是线程竞争的问题,咱们启用了一个新的异步线程,估计是避免了这种竞争,还需要好好研究下

    还有就是要注意Task.Run中func函数的异常处理,由于是异步线程,外部是捕获不到Task.Run中的异常的,如果有什么未处理的异常,可能会影响系统的稳定性

  • 相关阅读:
    【HDU3721】枚举+最长路
    满足要求的最长上升子序列(nlogn)
    Flask入门 表单Flask-wtf form原生 Bootstrap渲染(七)
    Flask入门之模板导入与块宏(六)
    Flask入门模板过滤器与测试器(五)
    Flask入门模板Jinja2语法与函数(四)
    Flask入门flask-script 蓝本 钩子函数(三)
    Flask入门request session cookie(二)
    Flask入门 flask结构 url_for 重定向(一)
    Django问卷调查项目思路流程
  • 原文地址:https://www.cnblogs.com/luludongxu/p/15954477.html
Copyright © 2020-2023  润新知