同步方法调用异步方法导致无响应死锁的问题
在同步方法中,由于没有await ,直接调用Task.Result()或Task.Wait()时,会导致死锁
如:
DoAsync().Wait(); async Task DoAsync() { await Task.Run(() => { }); }
必定会造成死锁,WCF,Webservice之类的,UI线程的
总结不会造成死锁的充分条件:
- 异步操作执行完后不需要回到原有线程(例如非 UI 线程和控制台线程);
- 异步操作不需要单独的线程执行任务。
为了防止真的有代码的调用者使用 Wait()、Result()
async Task DoAsync() { await Task.Run(() => { }).ConfigureAwait(false); }
这样,即便真的使用 DoAsync().Wait()
也不会发生死锁。注意,整个方法调用链都需要使用 .ConfigureAwait(false)
才能够防止线程切换时,在调用方的 Wait()
方法中发生死锁
指定了 ConfigureAwait(false)
,这意味着通知异步状态机 AsyncMethodStateMachine
并不需要使用设置好的 SynchronizationContext
(对于 UI 线程,是 DispatcherSynchronizationContext
)执行线程同步,而是使用默认的 SynchronizationContext
,而默认行为是随便找个线程执行后面的代码。于是,await Task.Run
后面的代码便不需要返回原线程,也就不会发生死锁问题。
备注:如果是这种方式,则在异步方法的Task.ConfigureAwait(false)语句之后的代码块中,获取不了原始上下文的某些变量,容易造成NullReferenceException空值引用异常。