我有 100 条并行化记录,从 1 到 100,现在我可以方便地使用 Parallel.For 并行执行它们,如下所示,这将基于计算资源工作

 Parallel.For(0, limit, i =>
    {
        DoWork(i);
    });

但是有一些限制,每个线程需要使用相同的数据实体,并且数据实体的数量有限,比如 10 个,它们是通过相互克隆并将它们保存在字典或列表等结构中而提前创建的。现在我可以使用以下代码限制并行化的数量:
 Parallel.For(0, limit, new ParallelOptions { MaxDegreeOfParallelism = 10 }, i =>
    {
        DoWork(i);
    });

但是问题是如何为每个传入的线程分配一个唯一的数据实体,这样数据实体就不会被任何其他当前执行的线程使用,因为线程和数据实体的数量是相同的,所以饥饿不是问题。我可以想办法,我为每个数据实体创建一个 bool 值,指定它是否在使用中,因此我们遍历字典或列表以找到下一个可用的数据实体并锁定整个分配过程,以便在给定时间为一个线程分配了一个数据实体,但在我看来,这个问题将有更优雅的解决方案,我的版本只是一种解决方法,而不是真正的解决方案。我的逻辑是:
Parallel.For(0, limit, new ParallelOptions { MaxDegreeOfParallelism = 10 }, i =>
        {
            lock(All_Threads_Common_Object)
            {
              Check for available data entity using boolean
              Assign the Data entity
            }
            DoWork(i);

            Reset the Boolean value for another thread to use it
        });

如果问题需要进一步澄清,请告诉我

最佳答案

您可以使用 concurrent collection 来存储 10 个对象。
每个 Worker 将拉出一个数据实体,使用它并返回。使用并发集合很重要,因为在您的场景中,普通集合不是线程安全的。

像这样:

var queue = new ConcurrentQueue<DataEntity>();
// fill the queue with 10 items

Parallel.For(0, limit, new ParallelOptions { MaxDegreeOfParallelism = 10 }, i =>
    {
        DataEntity x;
        if(!queue.TryDequeue(out x))
            throw new InvalidOperationException();
        DoWork(i, x);
        queue.Enqueue(x);
    });

或者,如果需要提供阻塞,请将事物包装在 BlockingCollection 中。

编辑:不要将其包装在循环中以继续等待。相反,像这样使用 BlockingCollection:
var entities = new BlockingCollection(new ConcurrentQueue<DataEntity>());

// fill the collection with 10 items

Parallel.For(0, limit, new ParallelOptions { MaxDegreeOfParallelism = 10 }, i =>
    {
        DataEntity x = entities.Take();
        DoWork(i, x);
        entities.Add(x);
    });

关于c# - Parallel.For 循环 - 为每个线程分配唯一的数据实体,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26729821/

10-13 00:08