我实现了这个想法,遍历了整个函数(包括所有子函数),并更改了 SqlConnections(和其他内容),以使其能够并行运行。我启动了整个程序,一切都很顺利和快速(仅这样就将该任务的时间缩短了约 45%)。
现在,昨天我们想尝试在更多数据上尝试同样的方法...但是我遇到了一些奇怪的问题:每当并行函数被调用时,它会执行它的工作...但有时线程中的一个会挂起至少 4 分钟(连接和命令的超时时间均为一分钟)。
如果我在此期间暂停程序,则会发现只有一个线程仍然活动,并且它在某处挂起。
connection.Open()
大约4分钟后,该程序继续进行,没有抛出错误(除了在输出框中显示某个异常发生但未被应用程序捕获而是在SqlConnection/SqlCommand对象的某个位置引起的消息)。
我可以杀掉MSSQLServer上的所有连接,但仍不会发生任何事情,同时MSSQLServer在这4分钟内也没有进行任何操作,所有连接都处于空闲状态。
以下是用于向数据库发送更新/插入/删除语句的过程:
int i = 80;
bool itDidntWork = true;
Random random = new Random();
while (itDidntWork && i > 0)
{
try
{
using (SqlConnection connection = new SqlConnection(sqlConnectionString))
{
connection.Open();
lock (connection)
{
command.Connection = connection;
command.ExecuteNonQuery();
}
itDidntWork = false;
}
}
catch (Exception ex)
{
if (ex is SqlException && ((SqlException)ex).ErrorCode == -2146232060)
{
Thread.Sleep(random.Next(500, 5000));
}
else
{
SqlConnection.ClearAllPools();
}
Thread.Sleep(random.Next(50, 110));
i--;
if (i == 0)
{
writeError(ex);
}
}
}
提醒一下,在较小的数据库上可能会出现死锁(错误号2146232060),如果发生死锁,我就必须让冲突语句在不同的时间发生。即使在小型数据库/小型服务器上也可以很好地工作。如果错误不是由死锁引起的,那么连接可能有问题,因此我正在清除所有损坏的连接。
类似的函数存在于执行标量、填充数据表/数据集(是的,这个应用程序已经有点老了)和执行存储过程中。
是的,所有这些都在并行循环中使用。
有人知道发生了什么吗?或者有什么办法可以找出发生了什么吗?
*关于命令对象:
它被传递给函数,当它被传递到函数中时,命令对象总是一个新对象。
关于锁定:如果我去掉锁定,我会得到数十个甚至数百个“连接已关闭”或“连接已打开”的错误,因为Open()函数只是从.NET的连接池获取连接。锁定确实能够按预期工作。
示例代码:
using(SqlCommand deleteCommand = new SqlCommand(sqlStatement))
{
ExecuteNonQuerySafely(deleteCommand); // that's the function that contains the body I posted above
}
我需要进行一些更正:它卡在这里。
command.Connection = connection;
至少我认为是这样的,因为当我暂停应用程序时,“步骤”标记会变成绿色并打开。
command.ExecuteNonQuery();
说这是下一个将要执行的语句。
*编辑3 为了确保,我刚刚开始了另一个测试,没有在连接对象周围加任何锁定...需要几分钟才能得到结果。
*编辑4 好吧,我错了。我删除了锁定语句...它仍然有效。也许第一次尝试时有一个重复使用的连接或其他什么东西。感谢指出这一点。
*编辑5
我有一种感觉,这只发生在对特定数据库过程的特定调用中。我不知道为什么。在C#方面,该调用与其他调用之间没有区别请参见编辑6。由于它在那个时候没有执行语句(我猜测。也许有人可以纠正我。如果在调试模式下,一行代码被标记为绿色(而不是黄色),则它还没有执行该语句,而是等待该行代码之前的语句完成,这正确吗?)所以很奇怪。
*编辑6 有3个命令对象一直被重用。它们在并行函数上面被定义。我不知道这有多糟糕/多少好。它们仅用于调用一个存储过程(每个存储过程都调用不同的存储过程),当然使用不同的参数和新连接(通过上述方法)。
*编辑7
好吧,只有在调用一个特定的存储过程时才会发生。除此之外,它卡在了连接对象的赋值上(下一行标记为绿色)。
正在尝试弄清楚原因。
*编辑8 耶,刚刚又在另一个命令中出现了。就是这样。
*编辑9 好了。问题解决了。'卡住'实际上是设置为10分钟的CommandTimeouts。它们仅适用于两个命令(我在编辑7和编辑8中提到的命令)。由于我在重组我的命令以使它们像devundef建议的那样时找到了它们两个,所以我将他的答案标记为解决我的问题。此外,他建议限制我的for循环使用的线程数量,这进一步加快了进程速度。 特别感谢Marc Gravell在星期六解释事情并与我保持联系;)