2015-11-10 41 views
2

我們有一個ASP.NET MVC網站,並將所有文本存儲在MongoDB中。 LocalizationTextManager類負責提供這些文本並在內部緩存它們。通常,這種方法非常快(< 5ms),如果結果存在於緩存中,則速度更快。MongoDB 2.0驅動程序和非異步代碼的潛在死鎖

我們有兩個方法:GetString和GetStringAsync。 GetStringAsync是首選,但我們在Razor中使用GetString方法,或者在某些不屬於異步上下文的罕見情況下使用。

MongoDB有一個異步驅動程序,我需要非同步實現它。因此我們嘗試了幾種方法。我確保我在代碼中的任何位置都設置了ConfigureAwait(false)。

FindOrAddTextFromRepositoryAsync(key).Result; 
Task.Run(async() => await FindOrAddTextFromRepositoryAsync(key)).Result; 
Task.Run(async() => await FindOrAddTextFromRepositoryAsync(key).ConfigureAwait(false)).Result; 

我知道我不需要任務內的ConfigureAwait(false)(因爲應該沒有同步上下文)。

我剛剛部署了該網站,並在部署後掛起。該過程重新啓動後,它正在工作。我之前做過轉儲,並發現有很多這些方法調用:

w3wp(4).DMP中的以下線程正在等待System.Threading.Monitor.Wait。 〜100 Thread threaded:

mscorlib_ni!System.Threading.ManualResetEventSlim.Wait(Int32, System.Threading.CancellationToken)+3ec 
mscorlib_ni!System.Threading.Tasks.Task.SpinThenBlockingWait(Int32, System.Threading.CancellationToken)+db 
mscorlib_ni!System.Threading.Tasks.Task.InternalWait(Int32, System.Threading.CancellationToken)+24a 
mscorlib_ni!System.Threading.Tasks.Task`1[[System.__Canon, mscorlib]].GetResultCore(Boolean)+36 
GP.Components.Globalization.LocalizationTextManager.GetString(System.String, System.String)+2f4 
GP.Components.Globalization.LocalizationTextManager.GetString(System.String, System.Globalization.CultureInfo)+8a 

我的問題是:我如何正確實現它?另一個想法是使用LimitedThreadsScheduler來確保它不會嚴重並行化。

回答

1

你的代碼中的主要問題是你的代碼不是異步的!

對於每個Task你創建你顯式調用Result財產

.Result; 

導致阻塞當前線程,直到任務完成。

如果您需要處理Task.Complete event,您可以使用continuation methodTaskto wait the tasks are pending的靜態方法。根本就不會阻止你的任務:

.ContinueWith((t) => { Console.WriteLine(t.Result); }, 
    TaskContinuationOptions.OnlyOnRanToCompletion); 

或:

Task.WaitAll(tasks); 

依我之見,在跟蹤GetString,非異步版本正在運行,並等待結果,所以其他線程不能做任何東西。我建議你嘗試調整setting the MaximumThreads for default thread pool的性能,將使用setting the MaximumThreads for default thread pool,併爲不同的任務調度程序分配同步和異步代碼,以便它們不會相互阻塞。其他選項的任務開始解釋這裏:Task.Run vs Task.Factory.StartNew

至於你的問題在最後,這裏是一個關於How to: Create a Task Scheduler That Limits Concurrency偉大的文章,所以你可以嘗試從那裏開始。

+0

我知道,這正是我所做的;) – SebastianStehle

+0

更新了一些想法的答案 – VMAtm

+0

@VMAtm只是要清楚,你會推薦什麼?使用委託來分配值,然後使用Task.Wait Any? –