C# 如果先提取任务,则异步任务会死锁
我正在使用Microsoft的C# 如果先提取任务,则异步任务会死锁,c#,async-await,task,task-parallel-library,deadlock,C#,Async Await,Task,Task Parallel Library,Deadlock,我正在使用Microsoft的asynchHelper()从同步上下文调用异步方法。这很好: Result r = AsyncHelper.RunSync(async () => await SomeClass.SomeMethodAsync()); 但是,如果我提取任务,然后尝试同步运行此提取的任务,则会遇到死锁: Task<Result> t = SomeClass.SomeMethodAsync(); Result r = AsyncHelper.RunSync(asy
asynchHelper
()从同步上下文调用异步方法。这很好:
Result r = AsyncHelper.RunSync(async () => await SomeClass.SomeMethodAsync());
但是,如果我提取任务,然后尝试同步运行此提取的任务,则会遇到死锁:
Task<Result> t = SomeClass.SomeMethodAsync();
Result r = AsyncHelper.RunSync(async () => await t);
Task t=SomeClass.SomeMethodAsync();
结果r=asynchHelper.RunSync(async()=>wait t);
为什么会发生这种情况,以及可以做些什么来运行此操作?
AsyncHelper。RunSync
使用确保在没有上下文的情况下调用其委托,从而使其可以安全地阻止(假设在线程池线程上调用委托是安全的)。在代码中,SomeMethodAsync
在线程池线程上执行,因此任何wait
s都不会执行
我们可以做些什么来实现这一目标
那么,您将使用第一个代码示例,而不是第二个
如果您希望有一个表示要运行的某些代码的构造,那么应该使用委托类型,例如Func
。例如:
Func<Task<Result>> func = () => SomeClass.SomeMethodAsync();
Result r = AsyncHelper.RunSync(func);
Func-Func=()=>SomeClass.SomeMethodAsync();
结果r=asynchHelper.RunSync(func);
对于异步代码,
任务
不代表要运行的某些代码;它表示一些已经启动的代码。使用Func
表示要运行的某些代码。asynchHelper。RunSync
使用确保在没有上下文的情况下调用其委托,从而使其可以安全地阻止(假设在线程池线程上调用委托是安全的)。在代码中,SomeMethodAsync
在线程池线程上执行,因此任何wait
s都不会执行
我们可以做些什么来实现这一目标
那么,您将使用第一个代码示例,而不是第二个
如果您希望有一个表示要运行的某些代码的构造,那么应该使用委托类型,例如Func
。例如:
Func<Task<Result>> func = () => SomeClass.SomeMethodAsync();
Result r = AsyncHelper.RunSync(func);
Func-Func=()=>SomeClass.SomeMethodAsync();
结果r=asynchHelper.RunSync(func);
对于异步代码,
任务
不代表要运行的某些代码;它表示一些已经启动的代码。使用Func
表示要运行的一些代码。通过调用\u myTaskFactory.StartNew
注意asynchHelper.RunSync
是如何运行SomeClass.SomeMethodAsync
。这确保开始执行SomeClass.SomeMethodAsync
的线程上没有安装SynchronizationContext。实际上,asynchHelper.RunSync
之所以有效,是因为它在没有安装SynchronizationContext
的线程上调用SomeMethodAsync
。避免这种情况的方法是确保在没有同步上下文的线程上调用SomeMethodAsync
,方法是使用类似于asynchHelper.RunAsync
…这看起来很像“syncoverasync”,在这种情况下是的:这是一个众所周知的问题,这正是您不打算这么做的原因“异步同步”。最终,你不能稍微异步;你需要一直异步。那么,这个问题唯一支持的答案就是删除异步同步:Result r=wait SomeClass.SomeMethodAsync();
(并使你正在处理的代码路径基于async
/[ValueTask][/code>)通过调用\u myTaskFactory.StartNew
,注意AsyncHelper.RunSync
如何运行SomeClass.SomeMethodAsync
。这确保开始执行SomeClass.SomeMethodAsync
的线程上没有安装SynchronizationContext。实际上,AsyncHelper.RunSync
可以工作,因为它调用SomeMethodAsync
在没有安装SynchronizationContext
的线程上。避免这种情况的方法是确保在没有SynchronizationContext
的线程上调用SomeMethodAsync
,方法是使用类似于AsynchHelper.RunAsync
…这看起来很像“异步同步”,在这种情况下是的:这是一个众所周知的问题,这正是为什么您不打算执行“异步同步”的原因。最终,你不能去稍微异步;你需要一路异步。那么,这个问题唯一受支持的答案就是删除异步同步:Result r=wait SomeClass.SomeMethodAsync()代码>(并使您正在处理的代码路径异步
/[ValueTask][]
-based)