我的问题是我显然使用了太多的任务(线程?)来调用查询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个事件,并且从未发生过崩溃或超时。听起来有点奇怪。
答案 0 :(得分:6)
您可以创建具有有限并发度TaskScheduler
的as 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以查看有多少活动连接。看看你是否可以尽快抓住使用 - 释放连接。