2017-10-16 5 views
1

Tpl Sample Click here to downloadTPL 구현 문제 내 프로젝트에 TPL을 구현하기 위해 노력하고

안녕, . 웹 클라이언트를 사용하여 5 개의 병렬 HTTP 호출을 만들었습니다.

달성하려는 목표. 5 개의 병렬 호출 중 하나가 "First"가 포함 된 문자열을 반환하면 나머지 호출을 중단하고 "First"를 반환하는 호출을 계속합니다. 내가 시도 무엇

은 :

나는 위의 샘플 코드를 부착했다. 여기서 나는 술어 (Predicate) 함수를 사용했다.

async Task<T> WhenAny<T>(IEnumerable<Task<T>> tasks, Func<T, bool> predicate) 
    { 
     var taskList = tasks.ToList(); 
     Task<T> completedTask = null; 
     do 
     { 
      completedTask = await Task.WhenAny(taskList); 
      taskList.Remove(completedTask); 
     } while (!predicate(await completedTask) && taskList.Any()); 

     return completedTask == null ? default(T) : await completedTask; 
    } 

그리고이 아래 전화 :

public async Task<string> methodname() 
    { 
     string sUrl = "https://abcd.com/test.php"; 
     Task<string> task1 = DownLoadData(sUrl); 
     Task<string> task2 = DownLoadData(sUrl); 
     Task<string> task3 = DownLoadData(sUrl); 
     Task<string> task4 = DownLoadData(sUrl); 
     Task<string> task5 = DownLoadData(sUrl); 
     var tasks = new[] { task1, task2, task3, task4, task5 }; 
     await WhenAny(tasks, t => t.Contains("First")); 

     return ""; 


    } 

을하지만 그렇지 충족 기준을. 제가 누락 된 부분을 제안하십시오. 어떤 도움을 주시면 감사하겠습니다.

+2

왜 당신은 Task.WhenAny 재발견 했습니까? 그리고 "휴식을 취하다"는 것은 무엇을 의미합니까? 서버 자체가 이러한 API를 제공하지 않는 한 * HTTP 서버 *에 처리를 중지 할 수 없습니다. –

+0

@PanagiotisKanavos 그렇지 않습니다. – Servy

+0

@Servy 나는 그것을 지금 본다. 이 경우에는 불행한 메소드 이름 –

답변

2

나는 당신이 확인보다는 반복적으로 동일한 URL을 확인하는 URL 목록이 있다고 가정 (?!)하지만 같은 방법은 어떤 경우 ....

I가 TPL Dataflow를 사용하려면 사용할 수 있습니다 이런 종류의 일. 이 기능을 사용하면 여러 동기화 작업 (예 : 문자열 다운로드)을 여러 개의 동기화 작업 (예 : 하위 문자열 "First"의 내용 확인)과 함께 연결하고 모든 방식의 '손잡이'를 제공하여 병렬 처리 수준, 버퍼 크기 등을 조절할 수 있습니다. 취소 토큰을 전달하여 추가 처리를 취소 할 수도 있습니다. 그래서 처음의이 취소 토큰 소스를 만들 수 있습니다 :

var cancellationSource = new CancellationTokenSource(); 

지금, 우리의 첫 번째 '블록'은 TransformBlock<string,string> 될 것이다. 두 번째 블록은 TransformMany<string,string> 블록 될 것

var downloadBlock = new TransformBlock<string,string>(
     async s => await DownloadData(s), 
     new ExecutionDataflowBlockOptions 
     { 
      MaxDegreeOfParallelism = 10, //allow up to 10 simulteneous downloads 
      BoundedCapacity = 100,  //allow the block to store up to 100 urls in a buffer 
      CancellationToken = cancellationSource.Token 
     }); 

: 그것은 URL 문자열을하고 DownloadData 함수를 호출하여 콘텐츠 문자열로를 '변형'이 블록의 일이다. 이 유형의 블록은 문자열을 문자열 모음으로 변환 할 수있게 해줍니다. 우리는 단지이에게 하늘의 콜렉션을 반환함으로써 우리의 기준을 충족하지 말아 콘텐츠 문자열을 필터링하는 작업을 제공 : 당신이 즉, 먼저 발견 한 내용 문자열로 뭔가를 (할 것 곳

var filterBlock = new TransformManyBlock<string,string>(
     s => { 
       if (s.Contains("First")) 
       { 
        return new string[]{s}; 
       } else 
       { 
        return new string[]{}; 
       } 
      }); // (we could also pass a cancellation token here) 

마지막 블록은 "First"가 포함 된 다운로드 콘텐츠). 우리가 한 모임 우리의 기준을 발견하면 우리는 또한 Cancel() 우리의 취소 토큰 소스가 어떤 새 URL의 처리를 시작하는 우리를 방지하기 위해 :

var finalBlock = new ActionBlock<string>(
     s => { 
       cancellationSource.Cancel(); 
       //do whatever you want with the content string here    
      }); 

우리가 블록을 결합하고 URL에 공급되어 지금 할 필요가있는 모든 :

downloadBlock.LinkTo(
    filterBlock, 
    new DataflowLinkOptions 
    { 
     PropagateCompletion = true // this flag ensures that if the first block completes ALL urls it signals to the nect block that no more will come 
    } 
); 
filterBlock.LinkTo(
    finalBlock, 
    new DataflowLinkOptions 
    { 
     PropagateCompletion = true, 
     MaxMessages = 1   //we are only interested in the first message that arrives in our final block 
    }); 

downloadBlock.Post("http://url.com/blah1"); 
downloadBlock.Post("http://url.com/blah2"); 
// etc... 

downloadBlock.Complete(); // this signals that we've ran out of Urls to process 
finalBlock.Completion.Wait(); //now wait for any messages we have 'in progress' to work through the pipeline 
+0

감사합니다. Stewart_R 나는이 솔루션으로 시험해보고 곧 업데이트 할 것입니다. 그 후에 나는 이것을 대답으로 표시 할 것입니다. –