问题描述
我有一个List<TaskClass> TaskList
项,我们可以使用并行循环进行迭代.
I have a List<TaskClass> TaskList
items that we can iterate over using a Parallel loop.
当TaskClass使用其自己的CompareTo(object obj)
方法实现IComparable时,列表中的项目将按特定顺序排序.因此,我们需要按顺序对项目进行操作.
The items in the list are sorted in a particular order as the TaskClass implements IComparable with its own CompareTo(object obj)
method.Thus we need the items acted upon in sequential order.
请注意,它们不必按顺序完成,只需按顺序开始.
因此,TaskList [0]应该首先启动;然后是TaskList [1],TaskList [2],...但是,我们不在乎TaskList [2]是先完成还是TaskList [0].
Thus TaskList[0] should be started first; then TaskList[1], TaskList[2], ...However, we don't care if TaskList[2] completes first, or TaskList[0].
这是我为减轻这种情况而想出的快速代码:
This is the quick code I've come up with to try and alleviate this:
//Construct a ConcurrentQueue and populate it with our SORTED list
//of TaskClass items so when we go through a parallel loop
//they are acted upon in sorted order. A parallel loop does not
//guarantee ordering, which we need to make sure tasks with a higher
//number are done first.
ConcurrentQueue<TaskClass> cq = new ConcurrentQueue<TaskClass>();
for (int x = 0; x < TaskList.Count; x++)
cq.Enqueue(TaskList[x]);
Parallel.For(
0,
cq.Count,
new ParallelOptions { MaxDegreeOfParallelism = DISystem.MaxConcurrentThreads },
x =>
{
TaskClass tc = null;
if (cq.TryDequeue(out tc))
{
TaskTypeManager ttm = new TaskTypeManager();
tc.Working = true;
tc.Started = DateTime.Now;
ttm.ProcessTaskItem(tc);
}
}
);
现在我认为问题是Parallel.For循环完成时,原始的List<TaskClass> TaskList
不会被更新为最新的值.
Now the issue I believe is when the Parallel.For loop completes, the original List<TaskClass> TaskList
will not have been updated with the latest values.
完成此任务的最佳方法是什么?
What is the best way to accomplish this?
具有如下修改的代码? (标有"//new"的行)
With modified code like the following? (lines marked with "//new")
ConcurrentQueue<TaskClass> cq = new ConcurrentQueue<TaskClass>();
for (int x = 0; x < TaskList.Count; x++)
cq.Enqueue(TaskList[x]);
List<TaskClass> NewTaskList = new List<TaskClass>(); //new
object lockObject = new Object(); //new
Parallel.For(
0,
cq.Count,
new ParallelOptions { MaxDegreeOfParallelism = DISystem.MaxConcurrentThreads },
x =>
{
TaskClass tc = null;
if (cq.TryDequeue(out tc))
{
TaskTypeManager ttm = new TaskTypeManager();
tc.Working = true;
tc.Started = DateTime.Now;
ttm.ProcessTaskItem(tc);
lock (lockObject) //new
{
NewTaskList.Add(tc);
}
}
}
);
NewTaskList.Sort(); //new
TaskList.Clear(); //new
TaskList = NewTaskList.ToList(); //new
还是有人有其他想法/建议/改进?
Or does anyone have any other ideas/suggestions/improvements?
谢谢!
推荐答案
可以吗?-否.也许大多数时候都可以,但是如果您确实需要的话就可以它命令.
Will this work? - No. Maybe most of the time, but not if you really need it ordered.
语句它们必须按顺序启动"存在一个固有的问题. 开始"是什么意思?您那里可能有比赛条件.请考虑以下修改:
There is an inherent problem with the statement "they do have to start in order". What do you mean with "start"? You probably have a race condition there. Consider this modification:
x =>
{
TaskClass tc = null;
if (cq.TryDequeue(out tc))
{
Thread.Sleep(random.Next(0, 1000));
TaskTypeManager ttm = new TaskTypeManager();
...
如您所见,顺序中唯一发生的事情是您的项目被出队-此后,并行性开始发挥作用,并且无法保证顺序.您需要某种方式同步到ProcessTaskItem
,直到您认为任务实际上是开始"的.
As you can see, the only thing happening in order is your items being dequeued - after that, parallelism kicks in and no order is guaranteed. You need some kind of synchronization into ProcessTaskItem
, up to the point where you consider the task to be actually "started".
这篇关于Parallel.对于使用ConcurrentQueue的List中的项目-可以工作吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!