任务太多会导致SQL db超时

时间:2011-03-29 16:58:01

标签: c# sql multithreading task task-parallel-library

我的问题是我显然使用了太多的任务(线程?)来调用查询SQL Server 2008数据库的方法。这是代码:

for(int i = 0; i < 100000 ; i++)
{  
  Task.Factory.StartNew(() => MethodThatQueriesDataBase()).ContinueWith(t=>OtherMethod(t));  
}

过了一会儿,我得到一个SQL超时异常。我希望将实际线程数保持低于(100)低于100000的缓冲区,称为“一次不超过10”。我知道我可以使用ThreadPool管理我自己的线程,但我希望能够使用 ContinueWith 的TPL之美。

我查看了Task.Factory.Scheduler.MaximumConcurrencyLevel,但它没有制定者。

我该怎么做?

提前致谢!

更新1
我刚刚测试了LimitedConcurrencyLevelTaskScheduler类(由Skeet指出)并且仍在做同样的事情(SQL超时)。
顺便说一句,这个数据库每天接收超过800000个事件,并且从未发生过崩溃或超时。听起来有点奇怪。

3 个答案:

答案 0 :(得分:6)

您可以创建具有有限并发度TaskScheduleras explained here,然后从中创建TaskFactory,并使用该工厂启动任务而不是Task.Factory }。

答案 1 :(得分:3)

任务与线程不是1:1 - 任务被分配线程以便从线程池中执行,并且线程池通常保持相当小(线程数== CPU核心数),除非任务/线程被阻塞等待长时间运行的同步结果 - 例如可能是同步网络调用或文件I / O.

因此,激活10,000个任务不应导致生成10,000个实际线程。但是,如果这些任务中的每一个都立即进入阻塞调用,那么您可能会遇到更多线程,但它仍然不应该是10,000个。

这里可能发生的事情是你一次性请求太多请求压倒SQL数据库。即使系统只为您的数千个任务设置了少量线程,如果调用的目标是单线程的,少数线程仍然会导致堆积。如果每个任务调用SQL数据库,并且SQL数据库接口或数据库本身通过单个线程锁协调多线程请求,则所有并发调用将堆积起来,等待线程锁进入SQL数据库执行。无法保证接下来会释放哪些线程来调用SQL数据库,因此您可能很容易得到一个“不幸”的线程,该线程开始等待早期访问SQL数据库,但不会进入SQL数据库调用在阻塞等待超时之前。

SQL后端也可能是多线程的,但由于许可级别而限制了并发操作的数量。也就是说,SQL演示引擎只允许2个并发请求,但完全许可的引擎支持数十个并发请求。

无论哪种方式,您都需要做一些事情来将并发性降低到更合理的水平。 Jon Skeet建议使用TaskScheduler限制并发听起来像是一个好的起点。

答案 2 :(得分:0)

我怀疑您处理数据库连接的方式有问题。 Web服务器可能有数千个并发页面请求在SQL活动的各个阶段运行。我敢打赌,减少并发任务数量的尝试确实掩盖了一个不同的问题。

您可以分析SQL连接吗?检查perfmon以查看有多少活动连接。看看你是否可以尽快抓住使用 - 释放连接。