源码:
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请求第三方接口的话,极其容易死锁
浙公网安备 33010602011771号