【发布时间】:2014-05-14 15:13:07
【问题描述】:
我有一个通过 Linq to Sql 与 SQL 服务器对话的多线程应用程序。当线程数人为地保持在 8 时,应用程序在四核 (Intel I-7) 机器上运行良好:
Parallel.ForEach(allIds,
new ParallelOptions { MaxDegreeOfParallelism = 8 },
x => DoTheWork(x));
什么时候线程的数量留给系统决定:
Parallel.ForEach(allIds, x => DoTheWork(x));
运行一段时间后,我得到以下异常:
超时。在获得一个之前的超时时间 来自池的连接。这可能是因为所有汇集的 正在使用连接并且已达到最大池大小。
我的应用中只有两种调用 SQL 的模式:
第一:
using (var dc = new MyDataContext())
{
//do stuff
dc.SafeSubmitChanges();
}
秒:
using (var dc = new MyDataContext())
{
//do some other stuff
DoStuff(dc);
}
.....
private void DoStuff(DataContext dc)
{
//do stuff
dc.SafeSubmitChanges();
}
我决定通过这种形式的逻辑来限制调用:
public static class DataContextExtention
{
public const int SQL_WAIT_PERIOD = 5000;
public static void SafeSubmitChanges(this DataContext dc)
{
try
{
dc.SubmitChanges();
}
catch (Exception e)
{
if (e.Message ==
"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.")
{
System.Data.SqlClient.SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(SQL_WAIT_PERIOD);
dc.SafeSubmitChanges();
}
else
{
throw;
}
}
}
}
这完全没有区别。一旦应用程序抛出第一个此类异常,应用程序中的各种随机位置(甚至与 SQL Server 无关的代码行)都会开始抛出此异常。
Q1:难道不是虔诚地使用 using 语句来防范这种情况吗?
Q2:出了什么问题,我该如何解决?
注意:大约有 250,000 个 ID。我还在MaxDegreeOfParallelism = 16 进行了测试,我得到了同样的异常。
【问题讨论】:
-
我不知道答案,但是你为什么要将
e.Message与一个常量字符串进行比较而不是检查e 的类型呢?这是不可接受的,尤其是任何语言都可以抛出异常。 -
平行
foreach中进行了多少次迭代?很可能由于某种原因您正在处理DataContext,但连接没有关闭。看看你能不能把dc.Connection.Close()放在using块中。 -
我认为连接的最大池大小为 100。尝试将
MaxDegreeOfParallelism设置为 100,看看是否可行,然后尝试 101 看看是否失败。即使您的DataContexts 被正确处理(我认为是这样),一旦您用尽了连接池,其他上下文也必须等待连接释放。由于数据库操作的等待时间相对较长,Parallel.ForEach很有可能正在启动超过 100 个并发操作。 -
@hatchet,它在 MaxDegreeOfParallelism = 16 时失败。在它失败之前我们甚至没有接近 100
-
多线程应用程序中“各种随机位置”的异常几乎总是由于未能正确同步对多线程之间共享资源的访问。
标签: c# linq-to-sql task-parallel-library using-statement timeoutexception