gpt4 book ai didi

c# - 限制通过并行任务库运行的事件任务数量的最佳方法

转载 作者:IT王子 更新时间:2023-10-29 04:02:30 28 4
gpt4 key购买 nike

考虑一个包含很多需要处理的作业的队列。队列的限制是一次只能获得 1 个工作,并且无法知道有多少个工作。这些作业需要 10 秒才能完成,并且需要大量等待来自 Web 服务的响应,因此不受 CPU 限制。

如果我用这样的东西

while (true)
{
var job = Queue.PopJob();
if (job == null)
break;
Task.Factory.StartNew(job.Execute);
}

然后它会疯狂地从队列中弹出作业,速度比它完成它们的速度快得多,耗尽内存并倒在它的屁股上。 >.<

我不能使用(我不认为)ParallelOptions.MaxDegreeOfParallelism因为我不能使用 Parallel.Invoke 或 Parallel.ForEach

我找到了 3 个替代方案

  1. 将 Task.Factory.StartNew 替换为

    Task task = new Task(job.Execute,TaskCreationOptions.LongRunning)
    task.Start();

    这似乎在某种程度上解决了问题,但我不是clear exactly what this is doing如果这是最好的方法。

  2. 创建 custom task scheduler that limits the degree of concurrency

  3. 使用像 BlockingCollection 这样的东西在开始时将作业添加到集合中,并在完成时删除作业以限制可以运行的数量。

#1 我必须相信正确的决定是自动做出的,#2/#3 我必须计算出我自己可以运行的最大任务数。

我是否理解正确 - 哪种方式更好,还是有其他方式?

编辑 - 这是我从下面的答案中得出的,生产者-消费者模式。

除了总体吞吐量目标外,作业出队的速度也不比处理速度快,并且没有多线程轮询队列(此处未显示,但这是一个非阻塞操作,如果从高频率轮询将导致巨大的事务成本多个地方)。

// BlockingCollection<>(1) will block if try to add more than 1 job to queue (no
// point in being greedy!), or is empty on take.
var BlockingCollection<Job> jobs = new BlockingCollection<Job>(1);

// Setup a number of consumer threads.
// Determine MAX_CONSUMER_THREADS empirically, if 4 core CPU and 50% of time
// in job is blocked waiting IO then likely be 8.
for(int numConsumers = 0; numConsumers < MAX_CONSUMER_THREADS; numConsumers++)
{
Thread consumer = new Thread(() =>
{
while (!jobs.IsCompleted)
{
var job = jobs.Take();
job.Execute();
}
}
consumer.Start();
}

// Producer to take items of queue and put in blocking collection ready for processing
while (true)
{
var job = Queue.PopJob();
if (job != null)
jobs.Add(job);
else
{
jobs.CompletedAdding()
// May need to wait for running jobs to finish
break;
}
}

最佳答案

我刚刚给了一个answer非常适用于这个问题。

基本上,TPL Task 类是用来安排 CPU 密集型工作的。它不是为阻止工作而设计的。

您正在使用不是 CPU 的资源:正在等待服务回复。这意味着 TPL 会错误地管理您的资源,因为它在一定程度上假设了 CPU 边界。

自己管理资源:启动固定数量的线程或LongRunning任务(基本相同)。根据经验确定线程数。

您不能将不可靠的系统投入生产。因此,我推荐 #1,但受到限制。不要创建与工作项一样多的线程。创建使远程服务饱和所需的尽可能多的线程。为自己编写一个辅助函数,它生成 N 个线程并使用它们来处理 M 个工作项。通过这种方式,您可以获得完全可预测且可靠的结果。

关于c# - 限制通过并行任务库运行的事件任务数量的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11138927/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com