普林克在大型名单上花费了大量时间

时间:2016-10-10 06:33:10

标签: c# c#-4.0 plinq

我有两个内存列表播放和消费者一个有15密耳的对象,另一个有3密耳。

以下是我要解雇的一些问题。

consumersn=consumers.AsParallel()
                    .Where(w => plays.Any(x => x.consumerid == w.consumerid))
                    .ToList();


List<string> consumerids = plays.AsParallel()
                                .Where(w => w.playyear == group_period.year 
                                         && w.playmonth == group_period.month 
                                         && w.sixteentile == group_period.group)
                                .Select(c => c.consumerid)
                                .ToList();


int groupcount = plays.AsParallel()
                      .Where(w => w.playyear == period.playyear 
                               && w.playmonth == period.playmonth 
                               && w.sixteentile == group 
                               && consumerids.Any(x => x == w.consumerid))
                      .Count();

我使用16核心机器和32 GB RAM,尽管如此......第一次查询需要大约20个小时才能运行..

我做错了什么..

真诚感谢所有帮助。

由于

2 个答案:

答案 0 :(得分:2)

第一个LINQ查询效率非常低,并行化只能帮助你。

说明:当您编写consumers.Where(w => plays.Any(x => x.consumerid == w.consumerid))时,这意味着,对于consumer中的每个对象,您可能会遍历整个plays列表以查找受影响的使用者。因此,最多300万消费者乘以1500万次播放= 45万亿次播放。即使在16个核心中,每个核心也有大约2.8万亿次操作。

所以,这里的第一步是按照consumerIds对所有播放进行分组,并将结果缓存到适当的数据结构中:

var playsByConsumerIds = plays.ToLookup(x => x.consumerid, StringComparer.Ordinal);

然后,您的第一个请求变为:

consumersn = consumers.Where(w => playsByConsumerIds.Contains(w.consumerid)).ToList();

即使没有任何并行化,此查询也应该更快。

我无法修复以下查询,因为我没有确切地看到您正在使用group_period完成的操作,但我建议您使用GroupByToLookup来创建所有组单程。

答案 1 :(得分:1)

第一个查询需要20个小时才能运行,因为每次plays.Any(x => x.consumerid == w.consumerid)不存在时,consumerid需要遍历整个15,000,000个游戏列表。

您可以通过在plays中构建所有使用者ID的哈希集来加快速度,如下所示:

var consumerIdsInPlays = new HashSet<string>(plays.Select(p => p.consumerid));

现在可以为O(1)查找重写第一个查询:

consumersn=consumers
    .AsParallel()
    .Where(w => consumerIdsInPlays.Contains(w.consumerid))
    .ToList();