2009-03-17 3 views
3

LINQ를 사용하여 상당히 큰 데이터 세트를 생성해야하는 경우 (몇 초 정도 소요될 수 있습니다.)) % '에 대한 사용에 대한 피드백을 생성합니다. 이것을 쉽게/선호하는 방법으로 사용할 수 있습니까?대용량 데이터 세트에서 LINQ 표현식을 실행하는 동안 진행 상황을보고하는 방법

예, 나는 1000 개 자동차 1000 개 트럭 목록 B에 목록 A를 갖고 있다고 나는 가능한 모든 주문 (자동차, 트럭) 쌍을 선택하려는 car.color == truck.color 링크이 :

var pairs = from car in A 
      from truck in B 
      where car.color==truck.color 
      select new {car, truck}; 

이제 어떤 점에서 이것은 중첩 된 foreach 루프의 집합으로 평가됩니다. 나는 그것이 완료되고 이상적으로 진행 막대 또는 무엇인가를 업데이트 할 때 완료되는 % '나이를보고 할 수 있기를 원합니다.

편집 : 나는이를 실행하고 있기 때문에이 작업을 수행

mPairs = pairs.ToList(); 

: 그냥 내 쿼리 후에, 나는 (실행 쿼리를 강제로)이 같은 목록으로 멤버 변수에 결과를 저장 UI 스레드에서 필요에 따라 LINQ 식을 계산할 때 UI 스레드가 멈추길 원치 않는 것처럼 백그라운드 작업자 스레드 (이것은 Silverlight BTW에 있음). 따라서 진전 상황을보고하고자하는 이유 UX는 기본적으로 이것이다 :

  1. 사용자는 엔진은 다음 작업 공간의 다른 모든 항목에 (많은) 연결 가능성을 확인하기 위해 백그라운드 스레드에서 차기 작업 공간
  2. 에 항목을 드래그.
  3. 엔진에서 UI를 계산하는 동안 새 연결을 허용하지 않고 새 항목이 다른 항목에 "연결할 수 있음"을 나타내는 보고서가 진행됩니다 (LINQ를 통해 아직 사용되지 않은 가능한 연결 경로가 모두 결정됨).
  4. 엔진이 계산 (쿼리)을 완료하면 해당 항목을 UI에 연결할 수 있으며 가능한 연결 경로가 나중에 사용할 수 있도록 로컬 변수에 저장됩니다 (예 : 사용자가 항목을 연결하기 위해 클릭하면 가능한 모든 경로가 표시됨). (유사한 과정이 항목의 삭제에 일어나야)가 추가 될 때

) 계산이 있었는지에 따라 강조된

답변

2

제대로 작동하는 데 사용 된 것은 DataContext의 어댑터로서 반환 된 항목 수가 계산되었습니다.

public class ProgressArgs : EventArgs 
{ 
    public ProgressArgs(int count) 
    { 
     this.Count = count; 
    } 

    public int Count { get; private set; } 
} 

public class ProgressContext<T> : IEnumerable<T> 
{ 
    private IEnumerable<T> source; 

    public ProgressContext(IEnumerable<T> source) 
    { 
     this.source = source; 
    } 

    public event EventHandler<ProgressArgs> UpdateProgress; 

    protected virtual void OnUpdateProgress(int count) 
    { 
     EventHandler<ProgressArgs> handler = this.UpdateProgress; 
     if (handler != null) 
      handler(this, new ProgressArgs(count)); 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     int count = 0; 
     foreach (var item in source) 
     { 
      // The yield holds execution until the next iteration, 
      // so trigger the update event first. 
      OnUpdateProgress(++count); 
      yield return item; 
     } 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

사용은

var context = new ProgressContext(
    from car in A 
    from truck in B 
    select new {car, truck}; 
); 
context.UpdateProgress += (sender, e) => 
{ 
    // Do your update here 
}; 

var query = from item in context 
      where item.car.color==item.truck.color; 

// This will trigger the updates 
query.ToArray(); 

유일한 문제는 당신이 총 수를 알지 못한다면 당신은 쉽게 백분율을 할 수 없다. 전체 개수를 계산하려면 종종 전체 목록을 처리해야하므로 비용이 많이 듭니다. 미리 총 개수를 알고 있으면 UpdateProgress 이벤트 처리기에서 백분율을 계산할 수 있습니다.

+0

나는이 접근법을 정말 좋아합니다. 내 LINQ 표현식은 몇 가지 중첩 된 것으로 구성되어 있습니다. - 적어도 너무 많은 업데이트 진행에 대한 오버 헤드가 발생하지 않기 때문에 어쨌든 내가 필요로하는 전체 진행률 표시기를 얻으려면 가장 바깥 쪽 목록에이 값을 넣을 수 있습니다. – caryden

4

편집 : 쿼리 표현식은 괄호를 허용하지 않기 때문에이 현재 작동하지 않습니다.

public class ProgressCounter 
{ 
    private readonly int total; 
    private int count; 
    private int lastPercentage; 

    public ProgressCounter(int total) 
    { 
     this.total = total; 
    } 

    public void Update() 
    { 
     count++; 
     int currentPercentage = (count * 100)/total; 
     if (currentPercentage != lastPercentage) 
     { 
      Console.WriteLine("Done {0}%", currentPercentage); 
      lastPercentage = currentPercentage; 
     } 
     return true; 
    } 
} 

... 

var progressCounter = new ProgressCounter(A.Count * B.Count); 

var pairs = from car in A 
      from truck in B 
      where progressCounter.Update() 
      where car.color==truck.color 
      select new {car, truck}; 

참고 항상 불쾌한 부작용의 사용 : 편집 ...

당신은 항상 진행 상황을 보여 주었다 "어떤 조합"을 선택하거나 where 절을 추가 할 수 없었다.

MoreLINQ에 일종의 연산자를 추가하려고 생각했습니다. 예를 들어 Pipe, Apply, Via 등이 있습니다.

1

Linq의 대부분은 지연 평가를 사용하여 수행됩니다. 따라서 쿼리는 결과를 foreach 할 때까지 실제로 실행되지 않습니다. 페어에서 결과를 가져올 때마다 질의가 평가됩니다.

즉, 결과를 반복하는 foreach 루프에 progres 만 표시 할 수 있습니다. 단점은 결과 집합의 크기를 계산하면 결과 집합을 반복하여 결과를 반복하고 쿼리를 실행한다는 것을 미리 알 수 없다는 것입니다.

0

그의 접근 방식이 훨씬 더 간결 할 것이라고 확신하지만, 글쎄 내 것이 존스와 비슷했다. 같은 방법으로 함께 해킹 할 수 있습니다 ..

var pairs = from car in A 
      from truck in B 
      let myProgress = UpdateProgress(...) 
      where car.color == truck.color 
      select new { car, truck }; 

private int UpdateProgress(...) 
{ 
    Console.WriteLine("Updating Progress..."); 
    return -1; 
} 

언급 한 바와 같이 쿼리는 반복 될 때까지 실행되지 않습니다. 이것은 쿼리 내에서 새 범위 변수를 만드는 추가 단점이기도합니다.

관련 문제