2011-03-29 102 views
3

我的問題是,我顯然使用太多的任務(線程?),調用查詢SQL Server 2008數據庫的方法。這裏是代碼:太多的任務導致SQL數據庫超時

for(int i = 0; i < 100000 ; i++) 
{ 
    Task.Factory.StartNew(() => MethodThatQueriesDataBase()).ContinueWith(t=>OtherMethod(t)); 
} 

過了一段時間,我得到一個SQL超時異常。我希望保持線程的實際數量低於(100000)到一個「一次不超過10個」的緩衝區。我知道我可以使用ThreadPool來管理我自己的線程,但是我希望能夠使用TPL的美麗與ContinueWith

我看着Task.Factory.Scheduler.MaximumConcurrencyLevel,但它沒有設置。

我該怎麼做?

提前致謝!

更新1
我只是測試了LimitedConcurrencyLevelTaskScheduler類(由雙向飛碟指出),仍然做同樣的事情(SQL超時)。
順便說一句,這個數據庫每天接收超過800000個事件,並且從來沒有發生過崩潰或超時事件。這聽起來有點奇怪。

+1

在24個時間段內的800,000個事件是同時少於100,000個的LOT。即使這只是8小時以上,它只會出現28秒的查詢...... – NotMe 2011-03-29 17:24:47

回答

5

您可以創建一個TaskScheduler併發,as explained here有限度的,然後創建一個TaskFactory,並使用該工廠開始,而不是Task.Factory的任務。

+0

我剛剛閱讀該文章:P。你有沒有使用過相同的實現(又名:好?)。我現在真的不想通讀實施。 – 2011-03-29 17:07:50

+0

Bah,Skeeted再次(即將鏈接到那篇文章) – Davy8 2011-03-29 17:09:43

+0

夥計們,我剛剛測試了LimitedConcurrencyLevelTask​​Scheduler類,仍然在做同樣的事情(SQL超時)。順便說一下,這個數據庫每天接收超過800000個事件,從未崩潰或超時。這聽起來有點奇怪。 – 2011-03-29 17:18:24

0

我懷疑你處理數據庫連接的方式有問題。 Web服務器可能會有數千個併發頁面請求在SQL活動的各個階段全部運行。我敢打賭,減少併發任務數量的嘗試實際上掩蓋了一個不同的問題。

你可以分析SQL連接嗎?檢查perfmon以查看有多少活動連接。看看你是否可以儘快抓取使用釋放連接。

3

帶線程的任務不是1:1 - 任務被分配線程在線程池外執行,並且線程池通常保持相當小(線程數量爲CPU核心數量),除非任務/線程被阻塞,等待長時間運行的同步結果 - 例如可能是同步網絡調用或文件I/O。

因此,旋轉10,000個任務不應導致產生10,000個實際線程。但是,如果這些任務中的每一個都立即陷入阻塞呼叫,那麼您可能會得到更多的線程,但它不應該是10,000。

這裏可能發生了什麼是你壓倒一切SQL請求一次太多的SQL數據庫。即使系統只爲您的數千個任務設置了少量線程,但如果調用的目標是單線程的話,少數線程仍可能導致堆積。如果每個任務都調用SQL數據庫,並且SQL數據庫接口或數據庫本身通過單個線程鎖來協調多線程請求,則所有併發調用都會堆積起來,等待線程鎖進入SQL數據庫執行。不能保證哪些線程將被釋放到下一個調用SQL數據庫中,因此您可能會很容易地以一個「不幸」的線程結束,該線程開始等待早期訪問SQL數據庫,但不會進入SQL數據庫調用在阻塞等待超時之前。

SQL後端也可能是多線程的,但由於許可級別限制了併發操作的數量。也就是說,SQL演示引擎只允許2個併發請求,但完全許可的引擎支持數十個併發請求。

無論採用哪種方式,您都需要採取措施將併發性降低到更合理的水平。 Jon Skeet提出的使用TaskScheduler來限制併發性的建議聽起來像是一個很好的開始。