2015-10-15 198 views
5

我必须缺少的东西SynchronizationContext明显,像一个僵局,但我不明白为什么会发生,不明白我怎么能避免它...Task.WaitAll与异步挂起/等待任务

所以,应用程序是Azure WorkerRole(就我所知,本质上,通常的Windows应用程序没有UI)。在应用方面,我想平行多项任务,和我的代码的原理版本的执行是这样的:

private async Task DoJob() 
{ 
    await SomeIoOperation(); 
} 


public void MethodExecutedByWorkerRoleInAnInfiniteLoop() 
{ 
    Log("Start"); 
    Task.WaitAll(DoJob(), DoJob(), DoJob()); 
    Log("End"); 
} 

在这里,我的想法是,我们使用默认SynchronizationContext操作的,所以我们应该避免例如,我们在类似的情况下会遇到的僵局。

但是,有时执行挂起 - 开始记录,结束不是天,直到我重新启动辅助角色。自然,DoJob无法运行那么久。奇怪的是,这并不是在工作者角色开始后立即发生 - 它可能需要几天或几周的正常操作直到它挂起。

我可以简化代码太多 - 也许重要的是什么发生在SomeIoOperation - 但我觉得这是明显的与SynchronizationContext误用有关。

请问SomeIoOperation.ConfigureAwait(false)有帮助吗?我甚至无法测试它,因为我不知道它是否工作,因为问题已修复,或者最终会在几天后终止。

想法?

+1

这篇文章将启发你的原因http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html – Gusdor

+2

加入'Log(SynchronizationContext.Current);'if它不是'null',你会知道你有'SynchronizationContext'问题。 – i3arnon

+0

'DoJob'将总是希望与调用上下文同步。 SomeIoOperation使用哪个上下文并不重要。 – Gusdor

回答

8

您正好处于SynchronizationContext的死锁状态。 只需使用WhenAll代替WaitAll

public async Task MethodExecutedByWorkerRoleInAnInfiniteLoop() 
{ 
    Log("Start"); 
    await Task.WhenAll(DoJob(), DoJob(), DoJob()); 
    Log("End"); 
} 

一切都将正常工作。

+1

该方法在循环中执行 - 调用者希望知道方法何时完成。国际海事组织,这个修订应该返回'任务'。 – Gusdor

+0

谢谢。我忘了在任务中更改无效。 –

+0

但是在我的循环中,我将不得不执行'MethodExecutedByWorkerRoleInAnInfiniteLoop()。Wait()' - 它会不会导致死锁吗?据我所知,'Microsoft.WindowsAzure.ServiceRuntime'中没有'RoleEntryPoint'的异步版本,所以我无法在任何地方等待我的'MethodExecutedByWorkerRoleInAnInfiniteLoop'。 –