我想创建一个简单的无限循环,将工作馈送到基于任务的工作池中。我也想限制当时最多创建的任务(我知道任务数不必等于线程数)。
我所拥有的是:
private readonly HashSet<Task> m_runningTasks = new HashSet<Task>();
private const int QueueTaskCount = 10; //our target task count
.... some method here ....
while (m_run){
IList<Job> jobs = null;
lock(m_runningTasks){
//determine missing job count here
targetCount = QueueTaskCount - m_runningTasks.Count;
if(targetCount>0)
jobs = GetSomeWork(targetCount);
}
if(jobs != null && jobs.Count > 0){
//i want to create jobs here in tasks
foreach(var job in jobs){
var task = new Task(job.Execute);
lock(m_runningTasks)
m_runningTasks.Add(task); //i could add continueTask instead of task here but that does not solve the problem
var continueTask = task.ContinueWith(x=> {lock(m_runningTasks){
m_runningTasks.Remove(x);
} };)
task.Run();
}
Task[] taskArray;
lock(m_runningTasks)
taskArray = m_runningTasks.ToArray()
Task.WaitAny(taskArray).Wait(); //HERE is the problem
}
}
我知道,当我创建continueWith一个新任务时,我需要阻止当前线程(创建和执行任务),直到它在m_running集合中的某些任务完成。但是,当我等待主要任务时,仍无法将它们从集合(m_runningTasks)中删除,因为continueTask尚未完成。
也有人在这个问题内建议continueWith:任务不等待ContinueWith完成,但是创建新任务,我不是在等待那个,而是在等待原始任务。
我的问题是完成后如何从其动作(方法)内部的集合中删除任务。
让我们让MaxDegreeOfParallelism(Aka QueuTaskCount)= 2
因此,在第一个迭代中,我们将连续启动任务A和B(这将A和B从列表中删除),将它们称为A'和B'。
所以在第一次迭代中
A- > A'
B- > B'
在那一行Task.WaitAny()行中,我们等待任务
A&B
可以说A结束,B继续
因此,我们再次进行迭代,因为Task.WaitAny已满载,并且我们继续进行下一个迭代
当计数时,我们现在应该创建多少个任务,我们就在这一行上执行targetCount = QueueTaskCount-m_runningTasks.Count;。
正如我们所说的A结束(又名runtocomplettiion)B奔跑
但是在集合(m_runningTasks)中,我们可能还是可能没有
A和B或仅B-取决于任务A'(它将A从集合中删除)
这是问题所在。在这种情况下,我不知道集合的状态是什么-但正确的状态只是B,因为A结束了。
有人(不记得知道谁了,删除了建议书)建议这不是我应该采取的最佳做法。
您必须从外部解决此问题-任务的调用者或创建者负责处理该问题。一种解决方案是利用Task.WhenAny()并删除内部while循环内的已完成任务(一次),但这可读性也不强。
我使用了带有MaxDegreeOfParallelism的ActionBlock并在其内部动作中填充任务的方式解决了这个问题-如此处所示:实现永无止境的任务的正确方法。(计时器与任务)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句