我想创建简单的无限循环,将作业提供给基于任务的作业池。 此外,我想限制当时最大创建的任务(我知道任务计数不必等于线程数)。
我拥有的是:
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
}
}
我知道当我创建continue时它有一个新任务但我需要阻止当前线程(创建和执行任务),直到m_running集合中的一些任务完成。但是当我等待主要任务时,他们无法从收集中删除(m_runningTasks),因为continueTask没有完成。
也有人建议继续在这个问题中: Task does not wait for ContinueWith to finish,但这创造了新的任务,我不是在等待,而是为原作。
我的问题是如何在完成后从其操作(方法)中删除集合中的任务。
让我们有MaxDegreeOfParallelism(Aka QueuTaskCount)= 2
因此,在第一次迭代中,我们将继续启动任务 A 和 B (从列表中删除A和B)让我们称之为 A'< / strong>和 B'。
所以在第一次迭代中我们有
A - &GT;的 A'
乙 - &GT;的 B'
在那一行Task.WaitAny()行中我们等待任务
A &amp;的乙
让我们说A结束,B继续
所以我们再次迭代,因为 Task.WaitAny 是完整的,我们继续下一次迭代
当我们计算时,我们应该创建多少任务,现在我们在这一行上做了 targetCount = QueueTaskCount - m_runningTasks.Count;
正如我们所说 A 结束(又名runtocomplettiion) B 正在运行
但是在集合(m_runningTasks)中我们仍然可能有或没有
A &amp; B 或仅 B - 取决于任务 A'(从集合中移除A)
这就是问题所在。 在这个itteration我不知道集合的状态是什么 - 但正确的状态只是 B 因为 A 结束。
答案 0 :(得分:0)
有人(不记得知道是谁,删除了答案提案)建议这不是我应该去的最佳做法。
您必须从外部解决此问题 - 任务的调用者或创建者负责处理它。 一个解决方案是利用Task.WhenAny()并在内部while循环中删除已完成的任务(当时一个),但这不是太可读也不是代码很好。
我解决了使用ActionBlock和MaxDegreeOfParallelism并在其内部操作中提供任务的问题 - 如下所示: Proper way to implement a never ending task. (Timers vs Task)