2012-08-24 8 views
4

코드 10 개 N 항목이 있습니다 (코드에서 가져와야 함). N 작업을 시작하여 데이터를 가져오고 각 작업에는 순서대로 10 개의 항목이 필요합니다. 나는 ConcurrentQueue<Item>에 항목을 넣었습니다. 그런 다음 항목은 스레드가 안전하지 않은 방법으로 하나씩 처리됩니다.비동기/대기 작업 및 WaitHandle

async Task<Item> GetItemAsync() 
{ 
    //fetch one item from the internet 
} 

async Task DoWork() 
{ 
    var tasks = new List<Task>(); 
    var items = new ConcurrentQueue<Item>(); 
    var handles = new List<ManualResetEvent>(); 

    for i 1 -> N 
    { 
     var handle = new ManualResetEvent(false); 
     handles.Add(handle); 

     tasks.Add(Task.Factory.StartNew(async delegate 
     { 
      for j 1 -> 10 
      { 
       var item = await GetItemAsync(); 
       items.Enqueue(item); 
      } 
      handle.Set(); 
     }); 
    } 

    //begin to process the items when any handle is set 
    WaitHandle.WaitAny(handles); 

    while(true) 
    { 
     if (all handles are set && items collection is empty) //*** 
      break; 
     //in another word: all tasks are really completed 

     while(items.TryDequeue(out item))   
     { 
       AThreadUnsafeMethod(item); //process items one by one 
     } 
    } 
} 

***이라고 표시된 문에 조건을 넣을 수 있는지 여부를 모르겠습니다. await을 작업에 사용하므로 여기서는 Task.IsCompleted 속성을 사용할 수 없으므로 작업이 곧 완료됩니다. 그리고 ManualResetEvent가 동일한 작업을 수행 할 수 있다고 생각하기 때문에 작업이 끝까지 실행되는지 여부를 나타내는 bool[]이 실제로보기 흉한 것처럼 보입니다. 아무도 나에게 제안을 줄 수 있습니까?

답변

3

글쎄,하지만 난 그것을 TPL Dataflow와 톤 쉽게 생각 : 이런 식으로 뭔가 작업을해야합니다. 같은

뭔가 : 모든

static async Task DoWork() 
{ 
    // By default, ActionBlock uses MaxDegreeOfParallelism == 1, 
    // so AThreadUnsafeMethod is not called in parallel. 
    var block = new ActionBlock<Item>(AThreadUnsafeMethod); 

    // Start off N tasks, each asynchronously acquiring 10 items. 
    // Each item is sent to the block as it is received. 
    var tasks = Enumerable.Range(0, N).Select(Task.Run(
     async() => 
     { 
     for (int i = 0; i != 10; ++i) 
      block.Post(await GetItemAsync()); 
     })).ToArray(); 

    // Complete the block when all tasks have completed. 
    Task.WhenAll(tasks).ContinueWith(_ => { block.Complete(); }); 

    // Wait for the block to complete. 
    await block.Completion; 
} 
1

대기 시간을 0으로 설정하여 WaitOne을 수행하여 상태를 확인할 수 있습니다. 당신이 구축이 직접,

if (handles.All(handle => handle.WaitOne(TimeSpan.Zero)) && !items.Any()) 
    break; 

http://msdn.microsoft.com/en-us/library/cc190477.aspx

+0

"현재 인스턴스가 신호를받을 때까지 현재 스레드를 차단"하므로 신호를 기다리는 차단 스레드가 10 개가됩니다. – Sebastian

+1

@Sebastian "설명 : timeout이 0이면 메서드가 차단되지 않고 대기 핸들의 상태를 테스트하고 즉시 반환됩니다." – jaggedSpire

+0

@jaggedSpire 좋아요, 내가 놓친 정보입니다. 고마워, 이제 WaitHandles를 확인하기위한 내 선호 솔루션입니다. – Sebastian

0

감사합니다. 마침내 나는 CountDownEvent이이 시나리오에 매우 적합하다는 것을 알았습니다.

for i 1 -> N 
{ 
    //start N tasks 
    //invoke CountDownEvent.Signal() at the end of each task 
} 

//see if CountDownEvent.IsSet here