我正在使用Microsoft的AsyncHelper
(source)从同步上下文中调用异步方法。这很好用:
Result r = AsyncHelper.RunSync(async () => await SomeClass.SomeMethodAsync());
但是,如果我提取任务,然后尝试同步运行此提取的任务,则会遇到死锁。:
Task<Result> t = SomeClass.SomeMethodAsync();
Result r = AsyncHelper.RunSync(async () => await t);
为什么会发生这种情况,以及如何进行此操作?
AsyncHelper.RunSync
使用thread pool hack来确保在没有上下文的情况下调用其委托,因此可以安全地进行阻塞(假设可以在线程池线程上安全地委托该委托)。在您的代码中,SomeMethodAsync
在线程池线程上执行,因此任何await
都不会capture a context。
如何进行此操作?
嗯,您将使用第一个代码示例而不是第二个代码示例。
如果要具有一个表示要运行的某些代码的构造,则应使用诸如Func<Task<T>>
的委托类型。例如:
Func<Task<Result>> func = () => SomeClass.SomeMethodAsync();
Result r = AsyncHelper.RunSync(func);
对于异步代码,Task<T>
并不代表要运行的某些代码;它表示已经启动的一些代码。使用Func<Task<T>>
代表要运行的某些代码。