2016-10-10 2 views
1

У меня есть два списка в играх с памятью, а у пользователей - один объект с 15 милями, а другой около 3 мил.plinq на больших списках, занимающих огромное время

является следующим несколькими запросами я стреляющими ..

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 Гб оперативной памяти, несмотря на это .. первый запрос занял около 20 часов, чтобы бежать ..

я делаю что-то неправильно ..

Вся помощь искренне признателен.

Благодаря

+1

Профайлер - ваш друг здесь. Но похоже, что вы выполняете операции 15M * 3M в своем первом запросе. –

ответ

2

Первый запрос LINQ очень неэффективно, распараллеливание может только помочь вам так много.

Пояснение: Когда вы пишете consumers.Where(w => plays.Any(x => x.consumerid == w.consumerid)), это означает, что для каждого объекта в consumer вы потенциально перейдете по всему списку plays, чтобы найти пострадавших потребителей. Так что это максимум 3 миллиона потребителей раз 15 миллионов игр = 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, но я бы предложил использовать GroupBy или ToLookup создать все группы в один проход.

+0

Спасибо .. Я буду читать на ToLookup. Что касается двух других запросов, они происходят внутри цикла foreach, и там нет предложения groupby. Единственная причина, по которой пользователи второго запроса запрашивают информацию, - это использовать его в третьем запросе. Так будет ли это правильно. Выберите (c => c.consumerid) во втором запросе .ToLookup (x => x.consumerid, StringComparer.Ordinal); и consumerids.Any (x => x == w.consumerid) для consumerids.Contains (w.consumerid) – Arnab

+0

Я предлагаю, что вы, вероятно, можете использовать 'GroupBy', чтобы избежать цикла для второго и третьего запросов. –

+0

Извините, Не понимаю, что вы имеете в виду, используя «GroupBy», чтобы избежать цикла. Не могли бы вы привести пример.Предложения where во втором и третьем запросах используют значения, поступающие из разных источников-group_period и (период и группа) соответственно. – Arnab

1

Первый запрос занял 20 часов, потому что plays.Any(x => x.consumerid == w.consumerid) должен пройти весь список из 15 000 000 игр каждый раз, когда consumerid не существует.

Вы можете ускорить этот процесс путем построения хэш-набор всех идентификаторов потребителей в plays, как это:

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

Теперь ваш первый запрос может быть переписан для O (1) поиска:

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

Могу ли я использовать Hashset для второго запроса и будет ли это быстрее? Также следует изменить consumerids.Any (x => x == w.consumerid) для consumerids.Contains (w.consumerid) в третьем запросе. будет ли это быстрее? Tx – Arnab

+1

@Arnab Второй запрос не ищет списки, поэтому он не будет быстрее. Третий запрос может быть выполнен быстрее, если вы превратите 'consumerids' в хэш-набор и используйте' Contains' вместо 'Any'. Вы также можете заменить 'Where (cond) .Count()' на 'Count (cond)'. – dasblinkenlight

Смежные вопросы