我怎样才能优化这些循环

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;
            }
        }