4

在我的多線程的Windows服務中,我在每個線程上打開數據庫的連接,然後我處理這些連接,但問題是當我執行查詢時,某些數據庫沒有關閉sys.sysprocesses表。線程的實體框架連接管理

我運行了兩個單元測試,看到了一些奇怪的行爲,首先我運行了一個有100個任務的循環,並在其中的每個人中打開一個新的連接。這些完成後(我通過WaitAll()看到),我看到一些連接仍然掛在數據庫中。 在第二次單元測試中,當我運行多個open/dispose而沒有並行執行時,它將它們處理得很好,並且在我的db中沒有掛起的連接。

問題是,在我的Windows服務中,這些掛起的連接正在被加起來,並且最終沒有更多的地方用於新的連接,並且db變得對用戶不可用。

這裏有代碼,第一個是平行的,第二個是不是:

[TestMethod] 
    public void TestMultiThreadedAccessToExplicitObjectContext() 
    { 
     int taskSize = 100; 
     List<Task> taskList = new List<Task>(); 
     int goodSources = 0; 
     for (int i = 0; i < taskSize; i++) 
     { 
      Task newTask = Task.Factory.StartNew(() => 
      { 
       System.Data.Objects.ObjectContext objectContext = new PersoniteEntities(); 
       objectContext.Connection.Open(); 
       objectContext.Dispose(); 
       Thread.Sleep(1200); 
      }); 

      taskList.Add(newTask); 
     } 

     Task.WaitAll(taskList.ToArray()); 
     GC.Collect(); 
     total += goodSources; 
    } 

[TestMethod] 
    public void TestMultiThreadedAccessToExplicitObjectContextInline() 
    { 
     System.Data.Objects.ObjectContext objectContext1 = new PersoniteEntities(); 
     objectContext1.Connection.Open(); 
     objectContext1.Dispose(); 

     System.Data.Objects.ObjectContext objectContext2 = new PersoniteEntities(); 
     objectContext2.Connection.Open(); 
     objectContext2.Dispose(); 

     System.Data.Objects.ObjectContext objectContext3 = new PersoniteEntities(); 
     objectContext3.Connection.Open(); 
     objectContext3.Dispose(); 

     System.Data.Objects.ObjectContext objectContext4 = new PersoniteEntities(); 
     objectContext4.Connection.Open(); 
     objectContext4.Dispose(); 

     System.Data.Objects.ObjectContext objectContext5 = new PersoniteEntities(); 
     objectContext5.Connection.Open(); 
     objectContext5.Dispose(); 
    } 

感謝

+3

這不是EF事情,也不是TPL事情。這是由於[連接池](http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx) – Aron

回答

3

使用連接池,每個工作進程(或在這種情況下,線程)都有它自己的連接池。因此,如果您將「最大池大小」設置爲3,並生成100x線程,則可能會有300個連接。

從別人

更多信息,誰也有類似的問題:

ODP.NET Connection Pooling Parameters

而且從MS有關連接池是如何工作的一些文檔和連接池的碎片化的explantion:

MSDN - SQL Server Connection Pooling (ADO.NET)

解決方案1 ​​

打開連接時,該鍵的值設置爲true在連接字符串

MSDN - Connection String - Pooling

在池關閉,當應用程序關閉任何新創建 連接將被添加到池。 在下次嘗試打開相同連接時,該連接將從池中抽取 。連接被認爲是相同的,如果他們有 相同的連接字符串。不同的連接有不同的 連接字符串。

此鍵的值可以是「true」,「false」,「yes」或「no」。

例如:

<add 
    name="AppEntities" 
    connectionString=" 
     metadata=res://*/App_Code.AppModel.csdl|res://*/App_Code.AppModel.ssdl|res://*/App_Code.AppModel.msl; 
     provider=System.Data.SqlClient; 
     provider connection string=&quot; 
     Data Source=.; 
     Initial Catalog=Example; 
     Integrated Security=True; 
     Pooling=False; 
     MultipleActiveResultSets=True 
     &quot;" 
    providerName="System.Data.EntityClient" 
/> 

解決方案2

它看起來像有可能涉及信號燈一種解決方法,這裏詳細:

Database connection pooling with multi-threaded service

1

假設您是在測試中運行的所有代碼,那麼您可能不會查看掛起的連接。這是連接池的正常行爲。

當您使用單個線程時.net可以重複使用與先前命令已關閉的物理連接相同的物理連接。使用多個線程時,必須打開多個物理連接才能處理並行請求。

Ps。您應該使用using語句而不是manual .Dispose,因爲如果打開後的內容拋出異常,您可能會冒連接打開的時間超過預期。因此,你可以用完連接。