我怎样才能优化这些循环
How can i optimise these loops
我有下面的代码片段,随着数据的增加,它需要很长时间才能 运行。
OrderEntityColection 是一个列表,samplePriceList 是一个列表
OrderEntityColection = 3 万笔交易
samplePriceList = 100 万个价格
轻松完成 10-15 分钟或更长时间
我已经用 1500 个订单和 300k 的价格对此进行了测试,但它也需要大约 40-50 秒,并且随着订单的增加,价格也会增加,甚至需要更长的时间
你能看到我如何改进它吗?我已经从一个大集合中将它减少到这些数字。
市场编号 = 整数
审计=字符串
foreach (var tradeEntity in OrderEntityColection)
{
Parallel.ForEach(samplePriceList,new ParallelOptions {MaxDegreeOfParallelism = 8}, (price) =>
{
if (price.MarketId == tradeEntity.MarketId)
{
if (tradeEntity.InstructionPriceAuditId == price.Audit)
{
// OrderExportColection.Enqueue(tradeEntity);
count++;
}
}
});
}
所以你想在内存中处理数据,好的 - 你需要对预先制定数据的方式保持聪明。首先,您将通过 MarketId 获取价格列表 - 所以首先创建它:
var pricesLookupByMarketId = samplePriceList.ToDictionary(
p => p.MarketId,
v => v.ToDictionary(k => k.Market));
现在你有一个 Dictionary<int,Dictionary<int,Price>>();
(注意我假设 MarketId 和 Audit 都是整数。如果不是,它应该仍然有效)
现在您的代码变得超级简单而且速度更快
foreach (var tradeEntity in OrderEntityColection)
{
if(pricesLookupByMarketId.ContainsKey(tradeEntity.MarketId)
&& pricesLookupByMarketId[tradeEntity.MarketId].ContainsKey(tradeEntity.InstructionPriceAuditId))
{
count++;
}
}
或者,如果您喜欢排长队
var count = OrderEntityColection.Count(tradeEntity => pricesLookupByMarketId.ContainsKey(tradeEntity.MarketId)
&& pricesLookupByMarketId[tradeEntity.MarketId].ContainsKey(tradeEntity.InstructionPriceAuditId))
正如评论中所指出的,这可以进一步优化以停止重复读取字典——但具体的实现取决于你最终想如何使用这些数据。
在并行循环中,您会遇到跳过某些项目的处理的情况。这非常昂贵,因为您依赖于该检查也发生在单独的线程上。我只是在处理之前先过滤掉结果,如下所示:
foreach (var tradeEntity in OrderEntityColection)
{
Parallel.ForEach(samplePriceList.Where(item=>item.MarketId == tradeEntity.MarketId && item.Audit == tradeEntity.InstructionPriceAuditId) ,new ParallelOptions {MaxDegreeOfParallelism = 8}, (price) =>
{
// Do whatever processing is required here
Interlocked.Increment(ref count);
});
}
附带说明一下,为了线程安全,您似乎需要将 count++
替换为 Interlocked.Increment(ref count)
。
在我朋友的帮助下设法做到这一点
var samplePriceList = PriceCollection.GroupBy(priceEntity=> priceEntity.MarketId).ToDictionary(g=> g.Key,g=> g.ToList());
foreach (var tradeEntity in OrderEntityColection)
{
var price = samplePriceList[tradeEntity.MarketId].FirstOrDefault(obj => obj.Audit == tradeEntity.Audit);
if (price != null)
{
count+=1;
}
}
我有下面的代码片段,随着数据的增加,它需要很长时间才能 运行。
OrderEntityColection 是一个列表,samplePriceList 是一个列表
OrderEntityColection = 3 万笔交易 samplePriceList = 100 万个价格
轻松完成 10-15 分钟或更长时间
我已经用 1500 个订单和 300k 的价格对此进行了测试,但它也需要大约 40-50 秒,并且随着订单的增加,价格也会增加,甚至需要更长的时间
你能看到我如何改进它吗?我已经从一个大集合中将它减少到这些数字。
市场编号 = 整数 审计=字符串
foreach (var tradeEntity in OrderEntityColection)
{
Parallel.ForEach(samplePriceList,new ParallelOptions {MaxDegreeOfParallelism = 8}, (price) =>
{
if (price.MarketId == tradeEntity.MarketId)
{
if (tradeEntity.InstructionPriceAuditId == price.Audit)
{
// OrderExportColection.Enqueue(tradeEntity);
count++;
}
}
});
}
所以你想在内存中处理数据,好的 - 你需要对预先制定数据的方式保持聪明。首先,您将通过 MarketId 获取价格列表 - 所以首先创建它:
var pricesLookupByMarketId = samplePriceList.ToDictionary(
p => p.MarketId,
v => v.ToDictionary(k => k.Market));
现在你有一个 Dictionary<int,Dictionary<int,Price>>();
(注意我假设 MarketId 和 Audit 都是整数。如果不是,它应该仍然有效)
现在您的代码变得超级简单而且速度更快
foreach (var tradeEntity in OrderEntityColection)
{
if(pricesLookupByMarketId.ContainsKey(tradeEntity.MarketId)
&& pricesLookupByMarketId[tradeEntity.MarketId].ContainsKey(tradeEntity.InstructionPriceAuditId))
{
count++;
}
}
或者,如果您喜欢排长队
var count = OrderEntityColection.Count(tradeEntity => pricesLookupByMarketId.ContainsKey(tradeEntity.MarketId)
&& pricesLookupByMarketId[tradeEntity.MarketId].ContainsKey(tradeEntity.InstructionPriceAuditId))
正如评论中所指出的,这可以进一步优化以停止重复读取字典——但具体的实现取决于你最终想如何使用这些数据。
在并行循环中,您会遇到跳过某些项目的处理的情况。这非常昂贵,因为您依赖于该检查也发生在单独的线程上。我只是在处理之前先过滤掉结果,如下所示:
foreach (var tradeEntity in OrderEntityColection)
{
Parallel.ForEach(samplePriceList.Where(item=>item.MarketId == tradeEntity.MarketId && item.Audit == tradeEntity.InstructionPriceAuditId) ,new ParallelOptions {MaxDegreeOfParallelism = 8}, (price) =>
{
// Do whatever processing is required here
Interlocked.Increment(ref count);
});
}
附带说明一下,为了线程安全,您似乎需要将 count++
替换为 Interlocked.Increment(ref count)
。
在我朋友的帮助下设法做到这一点
var samplePriceList = PriceCollection.GroupBy(priceEntity=> priceEntity.MarketId).ToDictionary(g=> g.Key,g=> g.ToList());
foreach (var tradeEntity in OrderEntityColection)
{
var price = samplePriceList[tradeEntity.MarketId].FirstOrDefault(obj => obj.Audit == tradeEntity.Audit);
if (price != null)
{
count+=1;
}
}