Parallel.For 在列表中,仅在开始时按顺序对项目进行操作

2024-01-08

我有一个List<TaskClass> TaskList我们可以使用并行循环迭代的项目。

列表中的项目按特定顺序排序,因为 TaskClass 使用自己的 IComparable 实现CompareTo(object obj)方法。 因此,我们需要按顺序执行的项目。

请注意,它们不必按顺序完成,只需按顺序开始即可。

因此TaskList[0]应该首先启动;然后任务列表[1],任务列表[2],... 但是,我们并不关心 TaskList[2] 是否先完成,还是 TaskList[0] 先完成。

这是我想出的快速代码来尝试缓解这个问题:

//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将不会更新为最新值。

实现这一目标的最佳方法是什么?

修改后的代码如下? (标有“//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

或者有人有任何其他想法/建议/改进吗?


这行得通吗? - No.也许大多数时候,但如果您确实需要订购,则不会。

“他们确实必须按顺序开始”这一说法存在一个固有的问题。你所说的“开始”是什么意思?你可能有一个竞争条件。考虑这个修改:

x =>
{
    TaskClass tc = null;
    if (cq.TryDequeue(out tc))
    {
        Thread.Sleep(random.Next(0, 1000));
        TaskTypeManager ttm = new TaskTypeManager();
         ...

正如您所看到的,唯一按顺序发生的事情是您的项目被出列 - 之后,并行性开始发挥作用,并且无法保证顺序。你需要某种同步ProcessTaskItem,直到您认为任务实际上“开始”为止。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Parallel.For 在列表中,仅在开始时按顺序对项目进行操作 的相关文章

随机推荐