如何在任务非常昂贵的任务中平衡并行性?

我有一个需要处理的对象列表。 所以说这个清单是所有客户的清单,我需要对它们进行CPU密集型计算。 虽然在计算之前和之后,我需要将数据提取并提交到数据库中,因此它不是纯粹的CPU任务。

所以我做的是

Parallel.ForEach(list, action);

行动的字面意思

1 Fetch customer data
2 Process calculate (time and memory intensive task)
3 Commit back customer data

这些代码过去很好用,但最近有时在处理大量记录的 多个客户时,系统会使内存不足。

那么有没有一种方法来平衡这个负载? 大多数客户的处理速度很快,但很少将所有资源都带走。 我可以避免其中几个一起运行吗?

我可以实现这一点的一种方法是,根据大小对列表进行排序,然后尝试选择第一个和最后一个项目,并自己控制并行性,但希望查看我在此处具有的选项。


既然你说在你实际完成之前你已经计算了一个大小的计算值,那么它就会大大简化操作。 在这一点上,您只需要一个同步原语,它不限制要执行的操作的数量,而是具有一些总权重值,并确保所有当前正在运行的操作的总和小于指定的权重值。 然后,您可以请求给定的操作以给定的权重值运行,并且直到有足够的未使用权重值才会实际运行。

没有现成的原语确实如此(信号量非常接近,但不是那里)。 但是,您可以很容易地从现有的同步原语中创建一个。

public class WeightedSemaphore
{
    public WeightedSemaphore(int totalWeight)
    {
        currentWeight = TotalWeight = totalWeight;
    }

    private ManualResetEvent signal = new ManualResetEvent(false);
    private int currentWeight;
    public int TotalWeight { get; }
    public int CurrentWeight { get { lock (signal) return currentWeight; } }

    public void Wait(int weight)
    {
        while (true)
        {
            lock (signal)
            {
                if (currentWeight >= weight)
                {
                    currentWeight -= weight;
                    return;
                }
            }

            signal.Reset();
            signal.WaitOne();
        }
    }
    public void Release(int weight)
    {
        lock (signal)
        {
            currentWeight += weight;
            signal.Set();
        }
    }
}

现在,您可以完成每项操作,确保在开始工作之前,先等待并提供其“大小”值。 从那里开始,只需要进行一些实验来确定当前系统可支持的总重量。

请注意,这样做的一个副作用是您会发现更快的操作往往会更快地获得优先级。 当一些空间被释放时,较短的操作更有可能与那里的空间一起运行,这意味着它将在更昂贵的操作之前预留该空间,甚至在运行时得到启动。 在许多情况下,这实际上是一个理想的属性,因为当您将更快的操作优先于更昂贵的操作时,平均响应时间实际上会减少。

链接地址: http://www.djcxy.com/p/8841.html

上一篇: How do I load balance parallelism in tasks wherein some tasks are very costly?

下一篇: Adding items to the collection being iterated over, or equivalent?