跨嵌套的ParallelFor循环同步

时间:2012-10-29 16:20:39

标签: c# .net-4.0 parallel-processing

我有一个类,其方法是运行嵌套的ParallelFor循环。基本上我正在迭代一个对象列表,然后是一个包含在每个对象属性中的列表。

根据为内循环中的每个对象计算的条件,我想添加到队列中。我正在使用“syncRoot”对象来尝试在添加到队列时保持并发性。

public class ParallelTest
{
    private static object syncRoot = new object();

    public void Test() {
       List<MyLog> queue = new List<MyLog>();
       ...
       Parallel.For(0, set.Count(), delegate(int i)
       {
           var obj = set[i];
           List<Connection> conns = obj.GetConnections();
           ...      
           Parallel.For(0, conns.Count(), delegate(int j)
           {    
               Connection c = conns[j];
               MyLog log = new MyLog();             
               ...                  
               if (condition)
               {                    
                   lock (syncRoot)
                   {
                       queue.Add(log);
                   }
               }
           }
       }

       Debug.WriteLine(queue.Count);
   }
}

我遇到的问题是我的所有对象似乎都没有被添加到队列中。我正在测试一组200个对象并将condition替换为true,所以我希望queue.Count为200.但是,我得到了奇怪的结果......有时200,有时198或199。

我在这里做错了什么?如何确保考虑每个线程?

2 个答案:

答案 0 :(得分:1)

这似乎是Linq的优秀候选人。

假设...表示的代码可以封装在带签名的方法中:

void Initialize(MyLog log, Connection conn, SomeUnknownType obj)

您的代码可以缩减为以下linq语句:

    var logs = set  
        .AsParallel()
        .SelectMany(
            obj =>
                obj.GetConnections()
                    .Select(conn => new{obj, conn}))
        .Select(x => { 
            var o = new{x.obj, x.conn, log = new MyLog()};
            Initialize(o.log, o.conn, o.obj); //or just do work inline
            return o;
        })
        .Where(x => x.obj... && x.conn...) //someCondition

    queue = logs.ToList();

看作set.Count()相对较高,并行set将确保工作在可用核心上得到合理划分。以后无需再次并行化。

答案 1 :(得分:0)

您可以使用ConcurrentQueue<T> Class代替List<T>。见http://msdn.microsoft.com/en-us/library/dd267265.aspx

了解更多信息。