我有一个服务,可以非常快速地轮询队列,以检查需要完成的更多“工作”。队列中的工作总是比单个工作者可以处理的更多。我想确保当服务已达到最大容量时,单个工作人员不会抓取太多工作。
假设我的工作者每隔N(ms)从队列中获取10条消息,并使用并行库在不同的线程上并行处理每条消息。这项工作本身非常重要。许多SQL Server查询甚至Azure表存储(http请求)都是针对单个工作单元进行的。
使用 TheadPool.GetAvailableThreads()正确的方法来限制服务可以获取的工作量吗?
我看到我可以访问可用的 WorkerThreads 和 CompletionPortThreads 。对于IO重工艺,是否更适合查看有多少CompletionPortThreads可用?我相信1000是每个进程可用的数字,无论cpu计数如何。
更新 - 知道我正在使用的队列是Azure队列可能很重要。因此,每个检查消息的请求都是async http请求,它返回下10条消息。 (并且花钱)
答案 0 :(得分:1)
我认为使用IO完成端口不是一个很好的方法来计算要抓取多少。
我认为理想的情况是,当下一组到达时,你的工作只是,所以你从来没有得到比你可以合理处理的更多的积压。
为什么不跟踪处理作业所需的时间以及获取作业所需的时间,并根据每次调整所获取的工作量,使用合适的最小/最大值来阻止工作变得疯狂你有一些非常便宜或非常昂贵的工作吗?
您还需要找出合理的最佳并行度 - 我不清楚它是真的 IO-heavy,还是仅仅是“异步请求重”,即您花费很多时候只是等待对复杂查询的响应,这些查询本身对你的服务资源来说很便宜。
答案 1 :(得分:1)
我在同一环境中一直在处理同样的问题。我最终给每个WorkerRole一个内部工作队列,实现为BlockingCollection<>。有一个线程监视该队列 - 当项目数量变少时,它会从Azure队列中请求更多项目。它总是要求最大数量的项目,32,以降低成本。如果队列为空,它还具有自动退避功能。
然后我有一组工作线程,我自己开始。它们处于循环中,将项目从内部工作队列中拉出。工作线程的数量是我优化负载的主要方式,因此我将其设置为.cscfg文件中的一个选项。我目前正在运行35个线程/工作者,但这个数字将取决于您的情况。
我尝试使用TPL来管理工作,但我发现管理负载更加困难。有时候TPL会进行并行化并且机器会感到无聊,有时候它会过度并行化,而Azure队列消息的可见性会在项目仍在工作时到期。
这可能不是最佳解决方案,但它似乎对我有效。
答案 2 :(得分:0)
我决定保留一个内部计数器,显示当前正在处理的消息数量。我使用Interlocked.Increment / Decrement以线程安全的方式管理计数器。
我会使用Semaphore类,因为每条消息都绑定到它自己的Thread但由于队列轮询器的异步性质和产生线程的代码而无法使用。