Parallel.For&获得下一个免费线程/工作者

时间:2015-07-29 08:36:11

标签: c# multithreading

我有以下并行化代码。我不确定如何设置workerIndex变量:

>

是否有某种机制可以说下一个工作线程ID是免费的?

2 个答案:

答案 0 :(得分:0)

你在new Worker()循环中只是Parallel.For,并将它们添加到w(你需要将w更改为并发列表)。

可能(如果它不是太复杂)将.Work(e)方法的内容移动到循环体,消除了对Worker类的需要。

修改

如果您将Worker数组更改为IEnumerable(即List<Worker>),则可以使用.AsParallel()使其平行。然后,您可以使用.ForAll(worker -> worker.Work())并行完成工作。这将要求您通过构造函数将element传递给worker。

答案 1 :(得分:0)

看起来对象池模式最适合您。您可以编写如下代码:

const int Limit = 3;
using (var pool = new QueueObjectPool<Worker>(a => new Worker(), Limit)) {
    element[] elements = GetArrayOfElements();
    var options = new ParallelOptions { MaxDegreeOfParallelism = Limit };

    Parallel.For(0, elements.Length, options, i => {
        element e = elements[i];
        Worker worker = null;
        try {
            worker = pool.Acquire();
            worker.Work(e);
        } finally {
            pool.Release(worker);
        }
    });
}

在启动过程中,每个元素都会等待可用的工作者,并且只有三个工作符将从表单开始初始化。这是简化的队列基础对象池实现:

public sealed class QueueObjectPool<TObject> : IDisposable {
        private readonly Queue<TObject> _poolQueue;
        private readonly Func<QueueObjectPool<TObject>, TObject> _factory;
        private readonly int _capacity;
        private readonly SemaphoreSlim _throttler;
        public QueueObjectPool(Func<QueueObjectPool<TObject>, TObject> factory, int capacity) {
            _factory = factory;
            _capacity = capacity;
            _throttler = new SemaphoreSlim(initialCount: capacity, maxCount: capacity);
            _poolQueue = CreatePoolQueue();
        }
        public TObject Acquire() {
            _throttler.Wait();

            lock (_poolQueue) {
                return _poolQueue.Dequeue();
            }
        }
        public void Release(TObject poolObject) {
            lock (_poolQueue) {
                _poolQueue.Enqueue(poolObject);
            }

            _throttler.Release();
        }
        private Queue<TObject> CreatePoolQueue() {
            var queue = new Queue<TObject>(_capacity);
            int itemsLeft = _capacity;

            while (itemsLeft > 0) {
                TObject queueObject = _factory(this);
                queue.Enqueue(queueObject);
                itemsLeft -= 1;
            }

            return queue;
        }
        public void Dispose() {
            throw new NotImplementedException();
        }
    }

此代码仅用于演示目的。在实际工作中,最好使用基于异步/等待的逻辑,这可以使用SemaphoreSlim.WaitAsync轻松实现,您可以用简单的循环替换Parallel.For。