2012-03-18 1 views
2

가능한 빨리 데이터를 직렬 프로세스로 가져 오는 응용 프로그램에서 작업하고 있지만 여러 작업 소스를 사용하여 해당 데이터를 가져옵니다. 또한 때로는 하나의 소스가 다른 소스보다 빠르지 만 어떤 소스가 될지는 알 수 없습니다. ContinueWhenAny (...)를 사용하고 있습니다. 계속 진행하고 호출하는 메서드에서 반환하려면 첫 번째 Task가 끝날 때까지 기다리십시오(). 그러나 먼저 데이터의 유효성을 확인한 다음 반환해야합니다 (또는 모든 작업이 완료되고 유효한 데이터가없는 경우). 지금은 내 코드가 먼저 완료되는 Task 인 경우 잘못된 데이터라도 반환합니다.작업 병렬 라이브러리를 사용하여 여러 작업을 실행하고 첫 번째 작업 후에 실제로 데이터를 반환하려면 어떻게해야합니까?

"ContinueWhenAny"와 같은 작업을 수행하는 방법이 있지만 Task.Result가 특정 조건을 충족하는 경우에만 그렇지 않으면 마지막 작업이 끝날 때까지 다음 작업/etc를 기다립니다.

또한 하나의 결과가 유효하면 다른 스레드가 취소된다는 것을 확인해야합니다. 이 부분은 이미 잘 작동합니다.

 ResultObject result = null; 
     var tokenSource = new CancellationTokenSource(); 
     var tasks = listOfSources 
       .Select(i => Task.Factory.StartNew(
        () => 
         { 
          i.CancellationToken = tokenSource.Token; 
          //Database Call 
          return i.getData(inputparameters); 
         }, tokenSource.Token)); 

     Task.Factory.ContinueWhenAny(
       tasks.ToArray(), 
       firstCompleted => 
        { 
         //This is the "result" I need to validate before setting and canceling the other threads 
         result = firstCompleted.Result; 
         tokenSource.Cancel(); 
        }).Wait(); 
     return result; 

어떤 아이디어 :

현재, 내 코드 (예외 처리 박탈 바로 볼트와 너트를) 다음과 같습니다? ContinueWhenAll을 사용하고 싶지 않습니다. 첫 번째 호출이 2 초 걸리고 두 번째 호출이 10 초가 걸리면 첫 번째 호출이 유효한 데이터를 반환하면 2 초 안에 직렬 프로세스로 돌아가고 싶습니다. 그렇지 않으면 10 초를 기다렸다가 결과에는 유효한 데이터가 있으며, 모든 태스크가 완료되고 유효하지 않은 결과를 리턴하는 경우에만 유효하지 않은 데이터를 리턴합니다.

--------- 업데이트 ---- 좋은 아이디어에 대해 zmbq에게 감사드립니다. 업데이트 된 (작동중인) 코드는 아래에 있으며 모든 요구 사항을 충족합니다. 그러나이 코드와 이전 코드의 차이점은 유효하지 않은 결과 자체를 반환하는 이전 코드가 아닌 작업이 유효한 결과를 생성하지 않으면이 코드가 null 결과를 반환한다는 것입니다. 이 버전도 변경하는 것은 어렵지 않지만,이 경우 내 목적을 위해 null을 반환하는 것이 좋습니다.

 ResultObject result = null; 
     var tokenSource = new CancellationTokenSource(); 
     var tasks = listOfSources 
       .Select(i => Task.Factory.StartNew(
        () => 
         { 
          i.CancellationToken = tokenSource.Token; 
          //Database Call 
          return i.getData(inputparameters); 
         }, tokenSource.Token)).ToArray(); 

     result = GetFirstValidResult(tokenSource,tasks); 

     return result; 


    private ResultObject GetFirstValidResult(CancellationTokenSource tokenSource, Task<ResultObject>[] tasks) 
    { 
     ResultObject result = null; 
     Task.Factory.ContinueWhenAny(
      tasks, 
      firstCompleted => 
       { 
        var testResult = firstCompleted.Result; 
        if(testResult != null && testResult.IsValid()) 
        { 
         result = testResult; 
         tokenSource.Cancel(); 
        } 
        else 
        { 
         var remainingTasks = tasks.Except(new[]{firstCompleted}).ToArray(); 
         if(remainingTasks.Any()) 
         { 
          result = GetFirstValidResult(tokenSource, remainingTasks); 
         } 
        } 
       }).Wait(); 
     return result; 
    } 

답변

4

당신의 firstCompleted 콜백 결과를 확인하고, 그 결과 불법 경우 나머지 작업에 ContinueWhenAny를 호출 할 경우에 그래서, 당신이 할 것입니다.

항상 그렇듯이 ZeroMQ을 살펴 보시기 바랍니다. 작업을 실행하고 결과가 합당한 경우 각 작업에서 출력 대기열에 메시지를 작성하도록합니다. 주 스레드는 대기열에서 차단되고 유효한 메시지가 있거나 모든 작업이 이미 끝났을 때 돌아옵니다.

+0

감사합니다. 이미이 케이스를 테스트 한 단위 테스트가 있으므로 작동하는 한 이것을 인정하고 표시 할 것입니다. –

+1

훌륭한 작품! ContinueWhenAny 논리를 자신의 함수로 옮겨서 더 이상의 작업이 없을 때까지 재귀 적으로 호출 할 수 있어야했습니다. 나는 그것을보고 싶어하는 사람을 위해 질문에 업데이트 된 코드를 포함시킬 것이다. –

관련 문제