2014-03-18 113 views
0

我有一个比较方法,我比较了两个集合的对象的一些属性。性能比较收集方法

public IEnumerable<Product> Comparer(IEnumerable<Product> collection, IEnumerable<Product> target, string comparissonKey) 
{ 
    var count = 0; 
    var stopWatch = new Stopwatch();     

    var result = new ConcurrentBag<Product>(); 

    var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 }; 

    Parallel.ForEach(collection, parallelOptions, obj => 
    { 
     count++; 
     if (count == 60000) 
     { 
      stopwatch.Stop(); 
      //breakpoint 
      var aux = stopwatch.Elapsed; 
     } 
     var comparableObj = obj; 
     comparableObj.IsDifferent = false; 
     bool hasTargetObject = false; 
     comparableObj.Exist = true; 

     Product objTarget = null; 
     foreach (Product p in target) 
     { 
      if (obj.Key == p.Key) 
      { 
       objTarget = p; 
       break; 
      } 
     } 

     if (objTarget != null) 
     { 
      //Do stuff 
     } 

     if (hasTargetObject) return; 

     if (comparableObj.IsDifferent) 
     { 
      //Do Stuff 
     } 
    }); 

    return result.ToList(); 
} 

如果我像这样执行这个方法,即时通讯获得几乎50秒的辅助变量中断断点。 如果我评论第二个foreach(在Parallel.Foreach内),它在不到1秒内就会中断。

我需要使用Key在目标集合中找到相应的对象,所以我做了第二个foreach。我使用LINQ where子句,但没有得到更好的结果。任何改善此方法性能的建议?

+2

如果您想通过键高效地查找问题,为什么不使用类似ConcurrentDictionary的东西? –

+0

嗨@JonSkeet,感谢您的回复。我检查它!但是,正如我在OP中评论的,没有办法让它更快(不改变集合类型)? – gog

+2

那么你从根本上得到了O(M * N)检查。这只是一种不适合高效加入集合的方法。我们也不知道任何有关'collection'和'target'的信息 - 如果'target'实际上是一个数据库支持的序列,例如,您可以通过一次实现集合而不是每个项目'collection'。 –

回答

1

您可以通过使用字典提高性能:

public IEnumerable<Product> Comparer(IEnumerable<Product> collection, IEnumerable<Product> target, string comparissonKey) 
    { 
     var count = 0; 
     var stopWatch = new Stopwatch(); 

     var result = new ConcurrentBag<Product>(); 
     var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 }; 

     // create a dictionary for fast lookup 
     var targetDictionary = target.ToDictionary(p => p.Key); 

     Parallel.ForEach(collection, parallelOptions, obj => 
     { 
      count++; 
      if (count == 60000) 
      { 
       stopwatch.Stop(); 
       //breakpoint 
       var aux = stopwatch.Elapsed; 
      } 
      var comparableObj = obj; 
      comparableObj.IsDifferent = false; 
      bool hasTargetObject = false; 
      comparableObj.Exist = true; 

      Product objTarget = null; 

      // lookup using dictionary 
      if (targetDictionary.TryGetValue(obj.Key, out objTarget)) 
      { 
       //Do stuff 
      } 

      if (hasTargetObject) return; 

      if (comparableObj.IsDifferent) 
      { 
       //Do Stuff 
      } 
     }); 

     return result.ToList(); 
    } 
+0

它完美的作品! – gog

+0

@ggui我很高兴它帮助:) – Bogdan