2015-10-15 197 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'。 –