C# 比较集合方法中的性能

C# 比较集合方法中的性能,c#,.net,linq,collections,C#,.net,Linq,Collections,我有一个方法比较器,用它比较两个集合的对象的一些属性 public IEnumerable<Product> Comparer(IEnumerable<Product> collection, IEnumerable<Product> target, string comparissonKey) { var count = 0; var stopWatch = new Stopwatch(); var

我有一个方法比较器,用它比较两个集合的对象的一些属性

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();
}
public IEnumerable比较器(IEnumerable集合、IEnumerable目标、字符串comparissonKey)
{
var计数=0;
var stopWatch=新秒表();
var结果=新的ConcurrentBag();
var parallelOptions=new parallelOptions{maxdegreeofpparallelism=Environment.ProcessorCount*2};
ForEach(集合,parallelOptions,obj=>
{
计数++;
如果(计数=60000)
{
秒表;
//断点
var aux=秒表。已过;
}
var可比obj=obj;
可比对象IsDifferent=假;
bool hasTargetObject=false;
可比对象存在=真;
产品对象目标=null;
foreach(目标中的产品p)
{
if(obj.Key==p.Key)
{
对象目标=p;
打破
}
}
如果(对象目标!=null)
{
//做事
}
if(hasTargetObject)返回;
if(可比对象不同)
{
//做事
}
});
返回result.ToList();
}
如果我像这样执行这个方法,我会在aux变量中断中得到接近50秒的断点。 如果我对第二个foreach(Parallel.foreach内部)进行注释,它将在不到1秒的时间内中断


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

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

    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();
    }
public IEnumerable比较器(IEnumerable集合、IEnumerable目标、字符串comparissonKey)
{
var计数=0;
var stopWatch=新秒表();
var结果=新的ConcurrentBag();
var parallelOptions=new parallelOptions{maxdegreeofpparallelism=Environment.ProcessorCount*2};
//创建字典以便快速查找
var targetDictionary=target.ToDictionary(p=>p.Key);
ForEach(集合,parallelOptions,obj=>
{
计数++;
如果(计数=60000)
{
秒表;
//断点
var aux=秒表。已过;
}
var可比obj=obj;
可比对象IsDifferent=假;
bool hasTargetObject=false;
可比对象存在=真;
产品对象目标=null;
//使用字典查找
if(targetDictionary.TryGetValue(obj.Key,out objTarget))
{
//做事
}
if(hasTargetObject)返回;
if(可比对象不同)
{
//做事
}
});
返回result.ToList();
}
如果钥匙确实是钥匙
然后使用HashSet,因为它有两个中间带并且吸烟很快

在类产品上,您需要覆盖GetHashCode和Equals
使用GetHashCode的键


如果您想通过键高效地查找内容,为什么不使用ConcurrentDictionary之类的工具呢?嗨@JonSkeet,谢谢您的回复。我查一下!但是,正如我在OP中所评论的那样,没有办法让它更快(不改变集合类型)?好吧,现在基本上你已经得到了一个O(M*N)检查。这只是一种不适合有效加入集合的方法。我们对
集合
目标
也一无所知-例如,如果
目标
实际上是一个数据库支持的序列,如果不想更改集合类型,您可能只需将集合物化一次,而不是针对
集合
@ggui中的每个项目,就可以改善问题,那么,如何对目标集合进行排序呢?然后,您可以只执行二进制搜索,而不是内部foreach循环。如果M=collection.count(),N=target.count(),N@m1o2,我实际上没有任何更改集合类型的限制。我只是想提高我在这个内部foreach循环中的性能。@ggui我很高兴它有帮助:)