2012-04-05 3 views
6

LINQ에서 Where은 스트리밍 운영자입니다. Where-as OrderByDescending은 비 스트리밍 연산자입니다. AFAIK, 스트리밍 운영자는 필요한 다음 항목 만 수집합니다. 비 스트리밍 연산자는 전체 데이터 스트림을 한 번에 평가합니다.스트리밍 운영자는 지연된 실행과 어떻게 다릅니 까?

나는 스트리밍 운영자를 정의하는 것과 관련이 없다. 나에게 그것은 Deferred Execution과 중복된다. 내가 custom 익스텐션을 작성하고 where 연산자와 orderby를 사용하여 그것을 소비 한 예제를 보자. 어느 경우

public static class ExtensionStuff 
{ 
    public static IEnumerable<int> Where(this IEnumerable<int> sequence, Func<int, bool> predicate) 
    { 
     foreach (int i in sequence) 
     { 
      if (predicate(i)) 
      { 
       yield return i; 
      } 
     } 
    } 
} 

    public static void Main() 
    { 
     TestLinq3(); 
    } 

    private static void TestLinq3() 
    { 
     int[] items = { 1, 2, 3,4 }; 

     var selected = items.Where(i => i < 3) 
          .OrderByDescending(i => i); 

     Write(selected); 
    } 



    private static void Write(IEnumerable<int> selected) 
    { 
     foreach(var i in selected) 
      Console.WriteLine(i); 
    } 

Where 조건을 만족하는 요소를 결정하기 위해 각 요소를 평가할 필요가있다. 오퍼레이터가 지연된 실행을 얻으므로 그 결과가 관련성이있는 것처럼 보입니다.

따라서 스트리밍 연산자의 중요성은 무엇입니까?

+5

'항목'에 약 20 억 개의 정수를 사용하여 다시 시도해보십시오. – cHao

+2

@cHao 또는 무한 시퀀스 또는 열린 네트워크 스트림에서 파생 된 시퀀스 –

+0

[더 구체적인 예] (http://codereview.stackexchange.com/a/9777/8246) –

답변

11

속도와 메모리라는 두 가지 측면이 있습니다.

.Take()과 같은 메서드를 사용하면 원래 결과 집합의 일부만을 소비 할 때 속도면이 더욱 분명 해집니다.

// Consumes ten elements, yields 5 results. 
Enumerable.Range(1, 1000000).Where(i => i % 2 == 0) 
    .Take(5) 
    .ToList(); 

// Consumes one million elements, yields 5 results. 
Enumerable.Range(1, 1000000).Where(i => i % 2 == 0) 
    .OrderByDescending(i => i) 
    .Take(5) 
    .ToList(); 

첫 번째 예는 단지 운영자 스트리밍 Take 호출 전에 만 평가 10 Take 전에 정지 값으로 1을 수득 결국 사용하므로

. 또한 한 번에 하나의 값만 메모리에로드되므로 메모리 사용 공간이 매우 작습니다.

두 번째 예제에서는 OrderByDescending이 스트리밍 중이 지 않으므로 Take는 첫 번째 항목을 가져오고 Where 필터를 통과 한 전체 결과는 정렬을 위해 메모리에 저장해야합니다. 이 작업은 오랜 시간이 걸리고 큰 메모리 사용량을 초래할 수 있습니다.

Take을 사용하지 않았더라도 메모리 문제가 중요 할 수 있습니다. 예를 들면 :

// Puts half a million elements in memory, sorts, then outputs them. 
var numbers = Enumerable.Range(1, 1000000).Where(i => i % 2 == 0) 
    .OrderByDescending(i => i); 
foreach(var number in numbers) Console.WriteLine(number); 

// Puts one element in memory at a time. 
var numbers = Enumerable.Range(1, 1000000).Where(i => i % 2 == 0); 
foreach(var number in numbers) Console.WriteLine(number); 
2

는 운영자 이익이 실행을 연기 때문에에만 해당 될 것으로 보인다 얻을 수 있다는 사실.

따라서 스트리밍 연산자의 중요성은 무엇입니까?

.l.e. 버퍼링/비 스트리밍 확장 메서드를 사용하여 무한 시퀀스를 처리 할 수는 없지만 스트리밍 확장 메서드 만 사용하여 이러한 시퀀스를 "실행할"수 있습니다 (중지 할 때까지). 예를 들어

테이크이 방법 :

public IEnumerable<int> GetNumbers(int start) 
{ 
    int num = start; 

    while(true) 
    { 
     yield return num; 
     num++; 
    } 
} 

당신은 잘 Where를 사용할 수 있습니다

foreach (var num in GetNumbers(0).Where(x => x % 2 == 0)) 
{ 
    Console.WriteLine(num); 
} 

OrderBy()는 철저하게를 방출하기 전에 결과를 열거해야하기 때문에이 경우에는 작동하지 않을 것입니다 단일 번호.

+1

Nitpick,하지만 그것은 무한합니다. 각 결과가 고유하지 않다는 것입니다. 결국 오버플로가되지만 랩핑되므로 무한한 횟수로 넘칠 수 있습니다. (당신이 체크 블록에 있지 않는 한) 당신이 원한다면'while (true) yield returns 4;를 가질 수 있습니다. – Servy

+0

아아 맞아 ;-) – BrokenGlass

2

그냥 명시해야합니다. 당신이 말한 경우에 스트림이 어디에 있든, orderby는 모든 것을 어쨌든 빨기 때문에 사실상 이점이 없다고 언급했습니다.그러나 스트리밍의 장점이 사용되는 경우 (다른 답변/설명에 예제가 제공됨)가 있으므로 모든 LINQ 운영자는을 최대한 활용하여 을 스트리밍합니다. Orderby 스트림 은 가능한 한 많이 일 수 있습니다. 스트림은 매우 효과적으로.

+0

스트리밍이'Where'와'OrderBy' 사이에있는 LINQ 연산자가 있습니까? –

+0

@ZevSpitz 나는 당신이 당신의 용어를 어떻게 정의하는지에 달려 있다고 생각합니다. 'SkipWhile'은 "스트리밍"의 양을 정의하는 방법에 따라 한정 될 수 있습니다. – Servy

+0

[MSDN] (https://msdn.microsoft.com/en-us/library/mt693095.aspx) 스트리밍은 결과를 한 번에 하나씩 구문 분석 할 수 있다고 정의합니다 (예 : '선택'). 비 스트리밍은 결과를 필요로합니다 첫 번째 값 (예 :'OrderBy')을 평가하기위한 모든 값. 이 정의에 따르면'SkipWhile'은 왜'Select'보다 덜 스트리밍을해야합니까? 첫 번째 반복에는 모든 값이 필요하지 않습니다. –

관련 문제