.net - 来自线程的 Entity Framework 连接管理

标签 .net entity-framework task-parallel-library connection-pooling

在我的多线程 Windows 服务中,我在每个线程上打开与 db 的连接,然后我处理这些连接,但问题是当我对 sys.sysprocesses 表执行查询时,有些连接没有在 db 上关闭。

我运行了两个单元测试并看到了一些奇怪的行为,首先我运行了一个包含 100 个任务的循环,然后在每个任务中打开一个新连接。这些完成后(我通过 WaitAll() 看到)我看到一些连接仍然卡在数据库中。
在第二个单元测试中,当我在没有并行执行的情况下运行多个 open/dispose 时,它​​会很好地处理它们并且我的数据库中没有挂起的连接。

问题是,在我的 Windows 服务中,这些挂起的连接被加起来,最后没有更多的地方可以放置新的连接,数据库变得对用户不可用。

这是代码,第一个是并行的,第二个不是:

    [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();
    }

谢谢

最佳答案

使用连接池,每个工作进程(或在本例中的线程)都有自己的连接池。因此,如果您将 Max Pool Size 设置为 3,并生成 100x 个线程,则可能有 300 个连接。

来自有类似问题的人的更多信息:

ODP.NET Connection Pooling Parameters

还有一些来自 MS 的关于连接池如何工作的文档,以及连接池碎片的解释:

MSDN - SQL Server Connection Pooling (ADO.NET)

解决方案 1

在连接字符串中关闭连接池

MSDN - Connection String - Pooling

When the value of this key is set to true, any newly created connection will be added to the pool when closed by the application. In a next attempt to open the same connection, that connection will be drawn from the pool. Connections are considered the same if they have the same connection string. Different connections have different connection strings.

The value of this key can be "true", "false", "yes", or "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

关于.net - 来自线程的 Entity Framework 连接管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16884559/

相关文章:

.net - 在不同项目中生成 POCO 类到具有 Entity Framework 模型的项目

c# - 何时使用 "await"关键字

c# - 违反主键 Entity Framework Code First

entity-framework - 更新多对多 Entity Framework 模型中的审计字段

c# - 简单的 Razor 模板语法,包括一个逗号来分隔名称

.net - 如何遍历WebHeaderCollection

ASP.NET MVC 什么线程池用于自定义任务?

c# - 使用单个并行 for 循环获取 Min、Max、Sum

c# - 使用 ServiceAccount.User 安装 Windows 服务以在用户凭据下运行但不提示

.net - 当 Transfermode = Stream 时向 WCF 流添加文件名和长度参数