C# 使用替代解决方案提高循环性能
我有两个列表对象,产品和价格C# 使用替代解决方案提高循环性能,c#,.net,linq,C#,.net,Linq,我有两个列表对象,产品和价格 var products = GetProdusts(predicate); var prices = GetAllProductPrices(); 用于填充产品。带价格对象的价格: Parallel.ForEach(products ,prod=> { prod.Prices= prices?.Where(pr =>pr.ProductId == prod.Id)?.ToList(); }); 这个循环需要很长时间。 谁能帮我改进一下吗 更
var products = GetProdusts(predicate);
var prices = GetAllProductPrices();
用于填充产品。带价格对象的价格:
Parallel.ForEach(products ,prod=> {
prod.Prices= prices?.Where(pr =>pr.ProductId == prod.Id)?.ToList();
});
这个循环需要很长时间。
谁能帮我改进一下吗
更新:
基于@Holger评论:
var priceDics = prices.GroupBy(p=>p.ProductId).ToDictionary(p=>p.Key ,p=>p.ToList());
Parallel.ForEach(products ,prod=> {
prod.Prices= priceDics?.Where(pr =>pr.Key== prod.Id)?.SelectMany(x=>x.Value).ToList();
});
现在性能得到了很大的提高。这里有一个简单的解决方案,它使用。它应该是如此之快,以至于并行不能使它更快
var lookup = prices.ToLookup(p => p.ProductId);
foreach (var product in products)
{
product.Prices = lookup[product.Id]?.ToList();
}
在循环中没有太多的计算。查找[…]
getter几乎是即时的,剩下的是为列表分配内存,并将每个列表的内容复制到新的列表中,这是一种高效的单CPU指令操作
更新:使用500000种产品和11000000种价格进行性能测试:
class Price { public int ProductId; }
class Product { public int Id; public List<Price> Prices; }
var products = Enumerable.Range(1, 500_000)
.Select(n => new Product() { Id = n }).ToList();
var prices = Enumerable.Range(1, 11_000_000)
.Select(n => new Price { ProductId = n % products.Count }).ToList();
var stopwatch = Stopwatch.StartNew();
var lookup = prices.ToLookup(p => p.ProductId);
Console.WriteLine($"Duration Lookup: {stopwatch.ElapsedMilliseconds:#,0} msec");
foreach (var product in products)
{
product.Prices = lookup[product.Id]?.ToList();
}
Console.WriteLine($"Duration Total: {stopwatch.ElapsedMilliseconds:#,0} msec");
class Price{public int ProductId;}
类产品{public int Id;public List Prices;}
var产品=可枚举范围(1500_000)
.Select(n=>newproduct(){Id=n}).ToList();
var价格=可枚举范围(1,11_000_000)
.Select(n=>newprice{ProductId=n%products.Count});
var stopwatch=stopwatch.StartNew();
var lookup=prices.ToLookup(p=>p.ProductId);
WriteLine($“持续时间查找:{stopwatch.elapsedmillesons:#,0}毫秒”);
foreach(产品中的var产品)
{
product.Prices=lookup[product.Id]?.ToList();
}
Console.WriteLine($“持续时间总计:{stopwatch.ElapsedMilliseconds:#,0}毫秒”);
输出:
查找持续时间:4051毫秒
总持续时间:4695毫秒
进程最慢的部分是填充查找
,这是不可并行的。为产品分配价格的最后一个循环可以并行化,但只需不到一秒钟。这里有一个简单的解决方案,它使用。它应该是如此之快,以至于并行不能使它更快
var lookup = prices.ToLookup(p => p.ProductId);
foreach (var product in products)
{
product.Prices = lookup[product.Id]?.ToList();
}
在循环中没有太多的计算。查找[…]
getter几乎是即时的,剩下的是为列表分配内存,并将每个列表的内容复制到新的列表中,这是一种高效的单CPU指令操作
更新:使用500000种产品和11000000种价格进行性能测试:
class Price { public int ProductId; }
class Product { public int Id; public List<Price> Prices; }
var products = Enumerable.Range(1, 500_000)
.Select(n => new Product() { Id = n }).ToList();
var prices = Enumerable.Range(1, 11_000_000)
.Select(n => new Price { ProductId = n % products.Count }).ToList();
var stopwatch = Stopwatch.StartNew();
var lookup = prices.ToLookup(p => p.ProductId);
Console.WriteLine($"Duration Lookup: {stopwatch.ElapsedMilliseconds:#,0} msec");
foreach (var product in products)
{
product.Prices = lookup[product.Id]?.ToList();
}
Console.WriteLine($"Duration Total: {stopwatch.ElapsedMilliseconds:#,0} msec");
class Price{public int ProductId;}
类产品{public int Id;public List Prices;}
var产品=可枚举范围(1500_000)
.Select(n=>newproduct(){Id=n}).ToList();
var价格=可枚举范围(1,11_000_000)
.Select(n=>newprice{ProductId=n%products.Count});
var stopwatch=stopwatch.StartNew();
var lookup=prices.ToLookup(p=>p.ProductId);
WriteLine($“持续时间查找:{stopwatch.elapsedmillesons:#,0}毫秒”);
foreach(产品中的var产品)
{
product.Prices=lookup[product.Id]?.ToList();
}
Console.WriteLine($“持续时间总计:{stopwatch.ElapsedMilliseconds:#,0}毫秒”);
输出:
查找持续时间:4051毫秒
总持续时间:4695毫秒
进程最慢的部分是填充查找
,这是不可并行的。为产品分配价格的最后一个循环可以并行化,但只需不到一秒钟。将一个集合转换为字典,然后迭代另一个集合。也许可以按ProductID对价格进行分组。您可以创建查找,这是分组和字典的良好组合。在生成的列表中,您应该提前创建(作为空列表),并逐个添加元素。因此,您可以避免这种嵌套迭代。这种情况不保证并行性。开销可能会超过收益。你只需要使用一个有效的数据结构()。@TheodorZoulias我测试了查找和字典,对我来说字典比查找快,当我使用并行循环时需要1分钟,没有并行循环时需要+5分钟。为什么不使用连接?您可能只得到一行结果,而且您没有一百万数据,速度可能更快。很难相信使用查找
而不使用并行性需要5分钟。不应该超过一秒钟。你有多少产品和产品价格?将你的一个收藏转换成一本字典,然后迭代另一个收藏。也许可以按ProductID对价格进行分组。您可以创建查找,这是分组和字典的良好组合。在生成的列表中,您应该提前创建(作为空列表),并逐个添加元素。因此,您可以避免这种嵌套迭代。这种情况不保证并行性。开销可能会超过收益。你只需要使用一个有效的数据结构()。@TheodorZoulias我测试了查找和字典,对我来说字典比查找快,当我使用并行循环时需要1分钟,没有并行循环时需要+5分钟。为什么不使用连接?您可能只得到一行结果,而且您没有一百万数据,速度可能更快。很难相信使用查找
而不使用并行性需要5分钟。不应该超过一秒钟。你们有多少种产品和产品价格?