同步方法中调取异步方法导致死锁

源码:

public static SOAResponse<DetectFaceResponse> DetectFace(string imgUrl)
      {
          var soaResponse = new SOAResponse<DetectFaceResponse>
          {
              Code = ErrorCode.对象不存在
          };
 
          try
          {
              var detectFaceRequest = new DetectFaceRequest
              {
                  Url = imgUrl
              };
              soaResponse.Body = CreateIaiClient().DetectFace(detectFaceRequest).
                  ConfigureAwait(false).GetAwaiter().GetResult();
              soaResponse.Code = ErrorCode.成功;
          }
          catch (Exception ex)
          {
              soaResponse.DefaultMessage = ex.Message;
              if (soaResponse.DefaultMessage.Contains("FailedOperation.ImageFacedetectFailed"))
              {
                  soaResponse.AddDefaultMessage("上传头像不存在人脸");
              }
          }
          return soaResponse;
      }

犯的错误: 异步编程忌讳同步方法调取异步方法,最大的注意点静态方法调取异步方法。
根据微软介绍ConfigureAwait(false)不会产生死锁了,这意味着通知异步状态机 AsyncMethodStateMachine 并不需要使用设置好的
SynchronizationContext(对于 UI 线程,是 DispatcherSynchronizationContext)执行线程同步,
而是使用默认的 SynchronizationContext,而默认行为是随便找个线程执行后面的代码。但是这个方法并没有生效
最后的解决方法是
1:全部改成异步编程
2:重写上下文请求,改成同步上下文
第一种改动量过大放弃
第二种从网上找了一个帮助类
    public static class AsyncHelpers
    {
        /// <summary>
        /// Execute's an async Task<T> method which has a void return value synchronously
        /// </summary>
        /// <param name="task">Task<T> method to execute</param>
        //public static void RunSync(Func<Task> task)
        //{
        //    var oldContext = SynchronizationContext.Current;
        //    var synch = new ExclusiveSynchronizationContext();
        //    SynchronizationContext.SetSynchronizationContext(synch);
        //    synch.Post(async _ =>
        //    {
        //        try
        //        {
        //            await task();
        //        }
        //        catch (Exception e)
        //        {
        //            synch.InnerException = e;
        //            throw;
        //        }
        //        finally
        //        {
        //            synch.EndMessageLoop();
        //        }
        //    }, null);
        //    synch.BeginMessageLoop();
 
        //    SynchronizationContext.SetSynchronizationContext(oldContext);
        //}
 
        /// <summary>
        /// Execute's an async Task<T> method which has a T return type synchronously
        /// </summary>
        /// <typeparam name="T">Return Type</typeparam>
        /// <param name="task">Task<T> method to execute</param>
        /// <returns></returns>
        public static T RunSync<T>(Func<Task<T>> task)
        {
            var oldContext = SynchronizationContext.Current;
            var synch = new ExclusiveSynchronizationContext();
            SynchronizationContext.SetSynchronizationContext(synch);
            T ret = default(T);
            synch.Post(async _ =>
            {
                try
                {
                    ret = await task();
                }
                catch (Exception e)
                {
                    synch.InnerException = e;
                    throw;
                }
                finally
                {
                    synch.EndMessageLoop();
                }
            }, null);
            synch.BeginMessageLoop();
            SynchronizationContext.SetSynchronizationContext(oldContext);
            return ret;
        }
 
        //internal static T RunSync<T>(Task<T> task)
        //{
        //    throw new NotImplementedException();
        //}
 
        private class ExclusiveSynchronizationContext : SynchronizationContext
        {
            private bool done;
            public Exception InnerException { get; set; }
            readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
            readonly Queue<Tuple<SendOrPostCallback, object>> items =
                new Queue<Tuple<SendOrPostCallback, object>>();
 
            public override void Send(SendOrPostCallback d, object state)
            {
                throw new NotSupportedException("We cannot send to our same thread");
            }
 
            public override void Post(SendOrPostCallback d, object state)
            {
                lock (items)
                {
                    items.Enqueue(Tuple.Create(d, state));
                }
                workItemsWaiting.Set();
            }
 
            public void EndMessageLoop()
            {
                Post(_ => done = true, null);
            }
 
            public void BeginMessageLoop()
            {
                while (!done)
                {
                    Tuple<SendOrPostCallback, object> task = null;
                    lock (items)
                    {
                        if (items.Count > 0)
                        {
                            task = items.Dequeue();
                        }
                    }
                    if (task != null)
                    {
                        task.Item1(task.Item2);
                        if (InnerException != null) // the method threw an exeption
                        {
                            throw new AggregateException(InnerException.Message, InnerException);
                        }
                    }
                    else
                    {
                        workItemsWaiting.WaitOne();
                    }
                }
            }
 
            public override SynchronizationContext CreateCopy()
            {
                return this;
            }
        }
    }
问题解决。
最后总结:异步编程避免在同步方法中调取异步方法,自己写的类库可能不会出现死锁现象,但是如果是通过http请求第三方接口的话,极其容易死锁

转载于:https://www.cnblogs.com/youxiaer/p/10938417.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值