2015-10-13 89 views
3

我使用SqlConnectionParallel.ForEach()運行多線程操作,從SQL Server數據庫獲取數據和下面正在發生的TCP連接:ADO.net不打烊速度不夠快

  • 我的包裹SqlConnectionusing聲明,以便連接正確處置。
  • 我的過程始終拋出SqlException包裹在一個AggregateException一段時間成功運行後(「建立到SQL Server的連接時發生網絡相關的或特定於實例的錯誤。」)
  • 我發現,這種情況大約2^14(16384)調用數據庫(總計,跨所有線程)。
  • 我啓動了perfmon,我可以看到這也是在引發異常的時候(「Connections Established」計數器)打開的TCP連接數。
  • 我確信在我的代碼中沒有連接泄漏 - 我查詢數據庫的地方很少,他們都正確地處理連接(事實上,沒有其他模式用於查詢數據庫比香草using(...)
  • 我關閉了連接池併發生相同的行爲。
  • 奇怪的是,如果我在SQL Server中刪除了一個使我的查詢速度很快的索引,那麼操作會成功完成(雖然速度很慢) - 不會引發異常。我觀察到,建立的連接數線性上升到大約13K,然後穩定了一段時間,然後有一段時間線性下降,這一切都在運行時進行。
  • 我的結論是,在建立索引的情況下,.net處理數據的速度比它能夠關閉連接並最終達到某種操作系統或.NET套接字最大閾值更快。如果沒有索引,.NET仍然保持着太多的連接,但是它有足夠的時間關閉它們,以便最大打開套接字閾值不被打中。

我不知道如何指示.NET關閉這些連接。我認爲當SqlConnection被丟棄時,這種情況會自動發生。

+0

特別奇怪的是,當連接池使用默認設置(100個連接)處於活動狀態時,該ADO可以打開更多的TCP連接 - 就好像池連接正在被拋棄一樣?!?! – SFun28

回答

1

這個問題似乎與如何打開連接。我使用這個構造

public SqlConnection(string connectionString, SqlCredential credential)

看來,ADO創建一個新的連接池,即使connectionString是相同的,credential封裝相同的憑據。我的猜測是,ADO以某種方式無法將憑據關聯到之前的調用(如果我通過使用引用相等來使用相同的憑證對象,這可能會起作用?在我的情況下,我會在每次調用時創建一個新的SqlCredential)。

由於每次創建一個新的池,TCP連接的氣球數量也會增加。我認爲這在連接池關閉時也是有意義的。可能有一些套接字或TCP設置在此處插入(保持聯絡?),並且操作系統保持連接開放以尊重這些設置。

0

即使連接對象正在釋放回池,非託管資源可能不會被釋放,直到執行垃圾回收。通過減慢命令(刪除該索引),您可以讓GC有足夠的時間將資源釋放回操作系統。

如果您沒有使用Async命令執行,您可以嘗試在線程級別緩存連接對象。然後平行操作將繼續重複使用相同的開放連接,而不是抓取新的套接字等。

我還沒有做過關於防止某些資源過度使用異步操作的任何測試。我相信他們會使用IO完成端口來防止阻塞。而且,你肯定不希望兩個使用相同連接對象的命令對象處於該狀態。

+1

也許定期調用GC.Collect()就足夠了,我可以避免緩存的複雜性。 – SFun28

+0

調用'GC.Collect'後跟'GC.WaitForPendingFinalizers()'似乎沒有幫助。 – SFun28