2017-10-16 23 views
1

Tpl Sample Click here to downloadTPLの実装の問題

こんにちは、 私は自分のプロジェクトにTPLを実装しようとしています。私は5つのパラレルHTTP呼び出しをWebクライアントを使用して作成しました。

私が達成しようとしていること。 5つのパラレルコールのいずれかが「First」を含む文字列を返した場合、残りのコールを強制終了し、「First」を返したコールを続行します。私が試してみました何

は:

私は、上記のサンプルコードを添付しています。ここでは、次の述語関数を使用しています。

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

@サーヴィー私は今それを見る。この場合の不幸なメソッド名 –

答えて

2

私はあなたがチェックではなく、繰り返し同じURLをチェックするURLのリストを持っていることを前提と(?!)が、同じ方法は、任意のイベント....

私は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) 

あなたが最初つまり、あなたが発見したコンテンツの文字列(と何かをする場所最後のブロックがあります「最初に」が含まれていることが判明したダウンロードされたコンテンツ)。我々Cancel()我々は基準1回の会議を見つけたら、新しい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私はこの解決策を試して、すぐにあなたを更新します。その後、私はこれを答えとしてマークします。 –