c# - 连接泄漏 (C#/ADO.NET) 即使使用使用创建的 SqlConnection
问题描述
我有一个程序在线程池上运行的任务中加载大量数据(每次迭代约 800K-1M 行)(请参阅下面的违规代码示例);同时运行的任务不超过 4 个。这是程序中唯一与该数据库建立连接的地方。在我的笔记本电脑(和其他同事相同的笔记本电脑)上运行该程序时,该程序运行良好。但是,我们可以通过远程桌面访问另一个工作站,它比我们的笔记本电脑更强大。该程序在其列表中失败了大约 1/3 到 1/2。所有任务都返回异常。
第一个例外是:“超时已过期。在从池中获取连接之前已经过了超时期限。这可能是因为所有池连接都在使用中并且达到了最大池大小。” 我尝试过在 StackOverflow 上搜索、搜索、搜索,并将头撞在桌子上,试图弄清楚这是怎么回事。一次运行的任务不超过 4 个,任何时候都不应有超过 4 个连接。
作为对此的回应,我尝试了两件事:(1)我在 conn.Open() 行周围添加了一个 try/catch,如果 InvalidOperationException 出现,它将清除池 - 这似乎有效[没有让它运行所有通过,但大大超过了以前的水平],但以性能为代价。(2) 我将 ConnectionTimeout 更改为 30 秒而不是 15 秒,这不起作用(但让它继续进行一点)。我也曾尝试过 ConnectRetryInterval=4(错误地选择了这个而不是 ConnectRetryCount)——这导致了另一个错误“最大请求数为 4,800”,这很奇怪,因为我们仍然不应该接近 4,800请求或连接。
简而言之,我很茫然,因为我无法弄清楚是什么导致了这种连接泄漏,只有在更高速度的计算机上。我也无法让该计算机上的 Visual Studio 直接调试 - 任何人可能对在哪里尝试解决这个问题的任何想法都将不胜感激。
(后续c#TaskFactory ContinueWhenAll在所有任务完成前意外运行)
private void LoadData()
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = "redacted";
builder.UserID = "redacted";
builder.Password = "redacted";
builder.InitialCatalog = "redacted";
builder.ConnectTimeout = 30;
using (SqlConnection conn = new SqlConnection(builder.ConnectionString))
{
//try
//{
// conn.Open();
//} catch (InvalidOperationException)
//{
// SqlConnection.ClearPool(conn);
// conn.Open();
//}
conn.Open();
string monthnum = _monthsdict.First((x) => x.Month == _month).MonthNum;
string yearnum = _monthsdict.First((x) => x.Month == _month).YearNum;
string nextmonthnum = _monthsdict[Array.IndexOf(_monthsdict, _monthsdict.First((x) => x.Month == _month))+1].MonthNum;
string nextyearnum = _monthsdict[Array.IndexOf(_monthsdict, _monthsdict.First((x) => x.Month == _month)) + 1].YearNum;
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = @"redacted";
cmd.Parameters.AddWithValue("@redacted", redacted);
cmd.Parameters.AddWithValue("@redacted", redacted);
cmd.Parameters.AddWithValue("@redacted", redacted);
cmd.CommandTimeout = 180;
SqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
Data data = new Data();
int col1 = reader.GetOrdinal("col1");
int col2 = reader.GetOrdinal("col2");
int col3 = reader.GetOrdinal("col3");
int col4 = reader.GetOrdinal("col4");
data.redacted = redacted;
data.redacted = redacted;
data.redacted = redacted;
data.redacted = redacted;
data.redacted = redacted;
data.Calculate();
_data.Add(data); //not a mistake, referring to another class variable
}
reader.Close();
cmd.Dispose();
conn.Close();
conn.Dispose();
}
}
解决方案
事实证明,这是一个没有仔细阅读文档的经典案例。我试图使用 ThreadPool.SetMaxThreads 将最大线程数限制为 4,但最大线程数不能小于处理器数。在它失败的工作站上,它有 8 个处理器。因此,从来没有上限,它运行任务计划程序认为合适的任务数量,最终达到连接池限制。
https://docs.microsoft.com/en-us/dotnet/api/system.threading.threadpool.setmaxthreads
推荐阅读
- python - 我在 python 代码中的 For 循环中犯了错误吗?模型精度太高,请仔细检查
- java - 从外部浏览器调用时的 HttpServletResponse 输出目标
- docker - 使用 docker 驱动程序在 minikube 中 Docker 本地私有注册表
- python - 为什么我的注册和登录系统在 python 中循环?
- java - 通过 WildFly 中的负载均衡器向 HornetQ 发送消息
- javascript - 如何在 JavaScript 中反转嵌套对象
- json - Flutter 错误:参数类型“动态”不能分配给参数类型“Iterable”
' - gnuplot - splitting a number into the integer and decimal parts GNUPLOT
- c# - Backus-Naur 形式的正则表达式
- javascript - PugJS 没有从 json 插入数字