本文介绍了Parallel.对于使用ConcurrentQueue的List中的项目-可以工作吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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中的项目-可以工作吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 09:16