Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 并行.For&;获取下一个可用线程/工作线程_C#_Multithreading - Fatal编程技术网

C# 并行.For&;获取下一个可用线程/工作线程

C# 并行.For&;获取下一个可用线程/工作线程,c#,multithreading,C#,Multithreading,我有以下并行代码。我不确定的是如何设置workerIndex变量: // Initializing Worker takes time & must be done before the actual work Worker[] w = new Worker[3]; // I would like to limit the parallelism to 3 for (int i = 0; i < 3; i++) w[i] = new Worker(); ... element[

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

// Initializing Worker takes time & must be done before the actual work
Worker[] w = new Worker[3]; // I would like to limit the parallelism to 3
for (int i = 0; i < 3; i++)
  w[i] = new Worker();
...
element[] elements = GetArrayOfElements(); // elements.Length > 3
ParallelOptions options = new ParallelOption();
options.MaxDegreeOfParallelism = 3;
Parallel.For(0, elements.Length, options, i =>
{
  element e = elements[i];
  w[workerIndex].Work(e); // how to set "workerIndex"?
});
//初始化工作者需要时间&必须在实际工作之前完成
工人[]w=新工人[3];//我想把平行度限制在3
对于(int i=0;i<3;i++)
w[i]=新工人();
...
element[]elements=GetArrayOfElements();//元素。长度>3
ParallelOptions=新的ParallelOption();
options.MaxDegreeOfParallelism=3;
Parallel.For(0,elements.Length,options,i=>
{
元素e=元素[i];
w[workerIndex].Work(e);//如何设置“workerIndex”?
});

是否有某种机制表明下一个工作线程id是空闲的?

您可以在
并行中创建
新的工作线程()
。For
循环,并将它们添加到
w
(您需要将w更改为并发列表)

可能(如果不太复杂的话)将
.Work(e)
方法的内容移动到循环体中,这样就不需要
Worker

编辑:


如果将
工作者
数组更改为
IEnumerable
(即
列表
),则可以使用使其并行。然后您可以使用来并行地完成工作。这需要您通过构造函数将
元素
传递给worker。

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

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);
        }
    });
}
const int Limit=3;
使用(var pool=new QueueObjectPool(a=>new Worker(),Limit)){
element[]elements=getArrayFelements();
var options=new ParallelOptions{maxdegreeofpparallelism=Limit};
Parallel.For(0,elements.Length,options,i=>{
元素e=元素[i];
Worker=null;
试一试{
worker=pool.Acquire();
工人工作(e);
}最后{
池.释放(工人);
}
});
}
在启动期间,每个元素都将等待可用的工作进程,并且从开始时只有三个工作进程将被初始化。以下是简化的队列基对象池实现:

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();
        }
    }
公共密封类QueueObjectPool:IDisposable{
专用只读队列_poolQueue;
私有只读功能工厂;
专用只读int_容量;
私有只读信号量limu节流器;
公共QueueObjectPool(函数工厂,整数容量){
_工厂=工厂;
_容量=容量;
_节流器=新信号量lim(initialCount:capacity,maxCount:capacity);
_poolQueue=CreatePoolQueue();
}
公开收购{
_throttler.Wait();
锁定(_poolQueue){
return_poolQueue.Dequeue();
}
}
公共无效释放(ToObject poolObject){
锁定(_poolQueue){
_排队(poolObject);
}
_节流器释放();
}
专用队列CreatePoolQueue(){
var queue=新队列(_容量);
int itemsLeft=_容量;
而(itemsLeft>0){
TObject queueObject=_工厂(此);
queue.Enqueue(queueObject);
itemsLeft-=1;
}
返回队列;
}
公共空间处置(){
抛出新的NotImplementedException();
}
}

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

如何
var workerIndex=i%w.Length
?@major mann-假设索引2的项目需要几个小时才能处理,但所有其他项目都很快。你很快就会遇到这样一种情况:一个线程在处理项目2时被卡住,而另一个线程在处理项目5时被卡住。@Damien_不信者如果是这样的话,那么,并行处理工人肯定不是你应该做的…@major mann-重点是夸大时间安排,以便你有希望看到为什么像
var workerIndex=i%w.Length
这样的东西不合适。你不知道每个线程都会被分配第1、第4、第7等项,也不知道每个线程都会在每次迭代中同时完成工作。@Damien_不相信者,我明白你现在说的,你是对的。正如代码中提到的,新的Wroker需要时间&必须事先完成。用其他选项更新。