2016-10-10 8 views
1

나는 메모리리스트에 2 개의 연극과 소비자가 있는데, 하나는 15 mil의 물건을, 다른 하나는 3 mil을 가지고있다. 거대한 시간을 들여 큰 목록에있는 plinq

다음

는 .. 첫 번째 쿼리를 실행하기 위해 약 20 시간이 걸렸다 내가 32기가바이트 RAM,이 Ɒ이 16 개의 핵심 기계를 사용하고

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(); 

.. 내가 발사있어 쿼리의 몇 가지 ..

뭔가 잘못하고 있습니다.

모든 도움을 진심으로 감사드립니다.

감사

+1

Profiler는 귀하의 친구입니다. 하지만 첫 번째 쿼리에서 15M * 3M 작업을 수행하는 것처럼 보입니다. –

답변

2

첫 번째 LINQ 쿼리는 매우 비효율적이다, 병렬화에만 너무 많은 당신을 도울 수 있습니다.

설명 : consumers.Where(w => plays.Any(x => x.consumerid == w.consumerid))을 작성하면 consumer에있는 모든 개체에 대해 plays 목록 전체를 반복하여 영향을받는 사용자를 찾을 수 있습니다. 따라서 최대 3 백만 명의 소비자가 1,500 만 건이 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 절이 없습니다. 두 번째 쿼리에서 consumerids를 얻는 유일한 이유는 세 번째 쿼리에서이를 사용할 수 있기 때문입니다. 그렇다면 두 번째 쿼리에서 .Select (c => c.consumerid)를 .ToLookup (x => x.consumerid, StringComparer.Ordinal);으로 변경하십시오. – Arnab

+0

내가 제안하는 것은'GroupBy'를 사용하여 두 번째 및 세 번째 쿼리의 루프를 피할 수 있다는 것입니다. –

+0

죄송합니다. 'GroupBy'를 사용하여 루프를 피하는 것이 무슨 뜻인지 이해할 수 없습니다. 예제를 제공해 주시겠습니까?두 번째 및 세 번째 쿼리의 where 절은 각각 다른 출처 (group_period 및 period 및 group)에서 오는 값을 사용합니다. – Arnab

1

plays.Any(x => x.consumerid == w.consumerid)consumerid이 없을 때마다 15,000,000 곡의 전체 목록을 처리해야하기 때문에 첫 번째 쿼리를 실행하는 데 20 시간이 걸렸습니다.

이 같은 plays 모든 고객 ID의 해시 세트를 구성하여이 속도를 높일 수 있습니다 : 이제 첫 번째 쿼리는 O (1) 조회 용으로 다시 작성 될 수

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

을 :

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

두 번째 쿼리에 Hashset을 사용할 수 있습니까? 그리고 더 빨라질까요 ?? 또한 consumerids.Any (x => x == w.consumerid)를 consumerids로 변경해야합니다. 세 번째 쿼리에서 (w.consumerid)를 포함합니다. 그게 더 빨라질까요 ?? Tx – Arnab

+1

@Arnab 두 번째 쿼리는 목록을 검색하지 않으므로 빠릅니다. 'consumerids'를 해시 집합으로 바꾸면 세 번째 질의를 더 빠르게 할 수 있으며'Any' 대신'Contains'를 사용합니다. 'Where (cond) .Count()'를'Count (cond)'로 대체 할 수도 있습니다. – dasblinkenlight