我有以下并行化代码。我不确定如何设置workerIndex变量:
>
是否有某种机制可以说下一个工作线程ID是免费的?
答案 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。