C# 并行。对于使用ConcurrentQueue的列表中的项目-这是否有效?

C# 并行。对于使用ConcurrentQueue的列表中的项目-这是否有效?,c#,parallel.for,concurrent-queue,C#,Parallel.for,Concurrent Queue,我有一个列表TaskList项,我们可以使用并行循环迭代这些项 当TaskClass使用自己的CompareTo(object obj)方法实现IComparable时,列表中的项按特定顺序排序。 因此,我们需要按顺序对项目进行操作 请注意,它们不必按顺序完成,只需按顺序开始即可 因此,应首先启动任务列表[0];然后是任务列表[1],任务列表[2]。。。 但是,我们不关心任务列表[2]是先完成,还是先完成任务列表[0] 这是我为缓解这一问题而提出的快速代码: //Construct a Conc

我有一个
列表TaskList
项,我们可以使用并行循环迭代这些项

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

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

因此,应首先启动任务列表[0];然后是任务列表[1],任务列表[2]。。。 但是,我们不关心任务列表[2]是先完成,还是先完成任务列表[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);
                }
        }
);
//构造一个ConcurrentQueue并用我们的排序列表填充它
//任务类的项,所以当我们通过并行循环时
//他们是按顺序行动的。并行循环不存在
//保证订购,我们需要确保任务具有更高的
//数字是先完成的。
ConcurrentQueue cq=新ConcurrentQueue();
对于(int x=0;x
{
TaskClass tc=null;
if(cq.TryDequeue(out tc))
{
TaskTypeManager ttm=新建TaskTypeManager();
tc.工作=真实;
tc.Started=DateTime.Now;
ttm.ProcessTaskItem(tc);
}
}
);
我认为现在的问题是,当Parallel.For循环完成时,原始的
List TaskList
将不会用最新的值进行更新

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

使用如下修改的代码?(标有“//新”的行)

ConcurrentQueue cq=新的ConcurrentQueue();
对于(int x=0;x
{
TaskClass tc=null;
if(cq.TryDequeue(out tc))
{
TaskTypeManager ttm=新建TaskTypeManager();
tc.工作=真实;
tc.Started=DateTime.Now;
ttm.ProcessTaskItem(tc);
lock(lockObject)//新建
{
新增(tc);
}
}
}
);
NewTaskList.Sort()//新的
TaskList.Clear()//新的
TaskList=NewTaskList.ToList()//新的
或者有人有其他想法/建议/改进吗

谢谢

这样行吗?-没有。可能大部分时间都是这样,但如果您真的需要订购,就不会

“他们必须按顺序开始”这句话有一个固有的问题。“开始”是什么意思?你可能在那里有比赛条件。考虑这种修改:

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

正如您所看到的,唯一按顺序发生的事情是您的项目被出列-在这之后,并行性开始出现,并且没有顺序得到保证。你需要一些同步到 PraseStasKiEM,直到你认为任务实际上是“开始”的时候。 为什么在结尾处使用
TaskList.Clear()
?对我来说似乎多余。否则看起来不错。我猜您正在创建一个新列表(
ToList)
),因为您将继续使用
NewTaskist
?否则,最好直接将其分配到
任务列表
(我的意思是,它已经排序了)。另一个想法是将
NewTaskList
制作成
ConcurrentBag
,使用自己的锁保存。但这意味着您需要
ToList()
将其分配给
TaskList
,然后执行
TaskList.Sort()
。。。有点难看。我不会用
NewTaskList
做任何进一步的事情。我正在使用
ToList()
来确保当此代码所在的方法完成时,
TaskList
中的对象不会被丢弃
TaskList
是一个类级变量,因此我们需要它们来持久化。我不确定他们会不会。这样我知道他们会的。在你设定的目标中似乎有一个根本性的缺陷:任务按顺序开始实际上意味着什么,为什么你认为你必须强加这个目标?正如Frank的回答所指出的那样,虽然您可以保证每个任务都按顺序出列(事实上,队列本身就是这样执行的!),但您没有足够的控制权来确保每个线程的调度超出此范围。一个线程可能会将一个任务出列,然后立即被抢占,导致其他线程在前一个线程取得任何进展之前将下一个任务出列并开始工作。你同意吗?对不起。在阅读了你的回复后,我可以看出“开始”是如何让人困惑的。让我看看能否澄清一下。我们需要按照列表中的顺序访问任务列表中的项目。我认为最好的方法是使用
ConcurrentQueue
,这样无论
并行中的哪个线程。因为
循环获得运行时的下一个片段,它只能从队列中按顺序访问下一个项目。希望能够确保按顺序访问这些项,就像我们在原始列表上运行单线程for循环一样。
x =>
{
    TaskClass tc = null;
    if (cq.TryDequeue(out tc))
    {
        Thread.Sleep(random.Next(0, 1000));
        TaskTypeManager ttm = new TaskTypeManager();
         ...