2013-12-20 2 views
2

항목이 순서대로 처리되도록 큐의 한 소비자가 정확히 원하는 비동기 버퍼 시스템을 구현하고 있습니다. 소비자는 주기적으로 큐를 확인하고 그 안에있는 모든 항목을 처리 한 다음 일정 시간 동안 "절전"해야합니다. Thread.Dleay()는 Thread.Sleep()과 달리 잠자는 동안 스레드를 소비하지 않기 때문에 Timer와는 달리 대기열 항목을 처리 할 때 휴면 간격보다 오래 걸리는 경우 새 스레드를 시작하지 않습니다 . 그러나 Task.Delay() while 루프를 사용하면 작업 시스템에서 원래 작업의 전체 연속 목록을 추적하는 경우 메모리 누수가 발생하는지 궁금합니다. 같은 참고로, 내 시스템이 보인다 : 나는 비동기 버퍼 시스템을 구현하고Task.Delay()가있는 루프가 메모리 누수를 생성합니까?

void EnqueueItem(Item item) { 
    lock (this._lock) { this._items.Add(item); } 
} 

async Task Consumer() { 
    while (true) { 
     await Task.Delay(interval).ConfigureAwait(false); 

     Item[] items = null; 
     lock (this._lock) { 
      if (this._disposed) { return; } 
      if (this._items.Count > 0) 
      { 
       items = this._items.ToArray(); 
       this._items.Clear(); 
      } 
     } 
     if (items != null) { Process(items); } 
    } 
} 

// in the constructor of the buffer 
this.Consumer(); 
+0

내가 이전에 타이머 방법을 사용하고 단지'Monitor.TryEnter' 방법을 사용했습니다 필요가 없습니다. 잠금을 얻을 수 없다면 아무 것도하지 않고 방금 메서드를 종료 할 수 있습니다. 즉, 스레드가 생성 될 수는 있지만 오래 가지 못합니다. 또는 각 프로세스 루프의 시작과 끝에서 타이머를 중지하고 시작할 수 있습니다. – Chris

+1

작업이 완료되고 코드가 작업 개체 참조를 삭제하면 작업의 연속 목록이 자동으로 가비지 수집됩니다. Task.Delay는 작업을 필요한 것보다 오래 실행되도록하는 것 이외에는 아무 효과가 없습니다. –

+0

질문과 관련이 없지만 생성자에서'Consumer()'를 호출하면'Process() '가 예외를 throw 할 때 어떤 일이 발생합니까? – svick

답변

3

그것은 당신이 자신의 종결 자

예를 기다리는 것보다 작업을 처리 할 수 ​​있습니다 꽉 루프에 그러나 경우, 메모리 누수가 발생하지 않습니다

var t = Task.Delay(interval); 
await t.ConfigureAwait(false); 
t.Dispose(); 

하지만 당신은 아마 싶지 않으며, (Do I need to dispose of Tasks? 참조)에

6

...

나는 강하게 당신이 기존의 것을 사용하는 것이 좋습니다. TPL Dataflow이 가장 좋습니다. 하지만 해당 플랫폼에서 사용할 수없는 경우 my AsyncProducerConsumerQueue 옵션을 사용할 수 있습니다.

이 설정을 사용하면 소비자는 ReceiveAsync/DequeueAsync을 사용하고 Task.Delay을 사용하지 않아도됩니다.

그건 그렇고, 당신이 묘사 한 것과 같은 메모리 누출이있을 것이라고 나는 믿지 않는다. 사실 이것을 확인하기 위해 프로파일 러에서 실제로 실행하지 않았습니다.

+0

TPL Dataflow를 사용하여 예제를 게시 하시겠습니까? 이 경우 단일 폴러가 주기적으로 일괄 적으로 처리하는 매우 많은 수의 항목을 큐에 넣고 있습니다 (항목이 많아 질 수 있도록 지연을 원합니다). 그래서 BlockingCollection과 같은 것을 사용하지 않고 있습니다. BlockingCollection은 한 번에 1 개의 객체를 대기열에 넣거나 빼는 데 중점을 둡니다. – ChaseMedallion

+2

확인; 일괄 처리 요구 사항을 알지 못했습니다. 이 경우 Reactive Extensions를 사용하고 싶을 것입니다. 이들은 시간 간격을 기반으로 일괄 처리 할 수있는 기본 제공 작업을 가지고 있습니다. –

+1

@ChaseMedallion Rx 대신에 BatchBlock을 사용하고 타이머에서 TriggerBatch()를 호출 할 수 있습니다. 또는 일괄 처리가 소비자의 속도에 의해 제어되어야하는 경우 [이 질문] (http://stackoverflow.com/q/20697649/41071)을보십시오. – svick

관련 문제