11

私はネットワークアプリケーションを作成しています。イベントベースの非同期パターンでのタスク並列ライブラリの使用

メッセージは、次のようなトランスポートを介して送信されます。

Network.SendMessage (new FirstMessage()); 

私はそうのように、このメッセージタイプが到着したときに呼び出されるイベントハンドラを登録することができます。

Network.RegisterMessageHandler<FirstMessage> (OnFirstMessageReceived); 

そして、イベントが発生します:

public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e) 
{ 
} 

私はネットワークアプリケーションのカスタム認証手順を書いていますが、完了するために約5つのメッセージが必要です。

タスク並列ライブラリを使用しない、私はそうのように、先行するイベントハンドラで、各手順の次のステップをコード化することを余儀なくされるだろう:

public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e) 
{ 
    Network.SendMessage(new SecondMessage()); 
} 

public void OnSecondMessageReceived(EventArgs<SecondMessageEventArgs> e) 
{ 
    Network.SendMessage(new ThirdMessage()); 
} 

public void OnThirdMessageReceived(EventArgs<ThirdMessageEventArgs> e) 
{ 
    Network.SendMessage(new FourthMessage()); 
} 

public void OnFourthMessageReceived(EventArgs<FourthMessageEventArgs> e) 
{ 
    // Authentication is complete 
} 

私は、周りのジャンプのアイデアを好きではありませんこれの一部とその一部をコード化するソースコード。理解して編集するのは難しいです。

タスクパラレルライブラリは、このソリューションを大幅に簡素化すると聞きました。

しかし、タスクパラレルライブラリを使用して読んだ例の多くは、アクティブというタスクのチェーンの開始に関連していました。

public void Drink() {} 
public void Eat() {} 
public void Sleep() {} 

Task.Factory.StartNew( () => Drink()) 
      .ContinueWith(() => Eat() ) 
      .ContinueWith(() => Sleep()); 

これは、各イベントハンドラメソッドのみが呼び出される私のイベントベースの非同期パターンから反対である:私は「アクティブ」によって何を意味するか、明示的に呼び出されたときに、各タスクはそうのように、始めることができるということですメッセージが受信されたとき。言い換えれば

、私はこのような何かすることはできません(を私はにしたい):

Task.Factory.StartNew( () => OnFirstMessageReceived() ) 
      .ContinueWith(() => OnSecondMessageReceived()) 
      .ContinueWith(() => OnThirdMessageReceived() ) 
      .ContinueWith(() => OnFourthMessageReceived()); 

私はthis articleを読んだが、私はかなりそれを理解していません。私が必要とするものはTaskCompletionSourceと関係があります。上記のコードブロックのようなイベントベースの非同期パターンからタスクを作成したければ、どのようになりますか?

答えて

20

あなたはTaskCompletionSourceについて言えば、それはEAP(イベントベースの非同期パターン)をTPLのタスクに変換するための鍵です。

これはここに文書化されています。ここではhttps://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/tpl-and-traditional-async-programming#exposing-complex-eap-operations-as-tasks

は単純化されたコードです:

public static class Extensions 
{ 
    public static Task<XDocument> GetRssDownloadTask(
     this WebClient client, Uri rssFeedUri) 
    { 
     // task completion source is an object, which has some state. 
     // it gives out the task, which completes, when state turns "completed" 
     // or else it could be canceled or throw an exception 
     var tcs = new TaskCompletionSource<XDocument>(); 

     // now we subscribe to completed event. depending on event result 
     // we set TaskCompletionSource state completed, canceled, or error 
     client.DownloadStringCompleted += (sender, e) => 
     { 
        if(e.Cancelled) 
        { 
         tcs.SetCanceled(); 
        } 
        else if(null != e.Error) 
        { 
         tcs.SetException(e.Error); 
        } 
        else 
        { 
         tcs.SetResult(XDocument.Parse(e.Result)); 
        } 
     }; 

     // now we start asyncronous operation 
     client.DownloadStringAsync(rssFeedUri); 
     // and return the underlying task immediately 
     return tcs.Task; 
    } 
} 

さて、あなたはこれらの操作の連鎖を作るために、行う必要があるすべては、(ちょうどあなたの継続を設定することですこれは現時点では非常に快適ではない、とC#5のawaitと非同期はそれでたくさんのに役立ちます)

ので、このコードは次のように使用することができます:

public static void Main() 
{ 
    var client = new WebClient(); 

    client.GetRssDownloadTask(
     new Uri("http://blogs.msdn.com/b/ericlippert/rss.aspx")) 
     .ContinueWith(t => { 
      ShowXmlInMyUI(t.Result); // show first result somewhere 
      // start a new task here if you want a chain sequence 
     }); 

    // or start it here if you want to get some rss feeds simultaneously 

    // if we had await now, we would add 
    // async keyword to Main method defenition and then 

    XDocument feedEric = await client.GetRssDownloadTask(
     new Uri("http://blogs.msdn.com/b/ericlippert/rss.aspx")); 
    XDocument feedJon = await client.GetRssDownloadTask(
     new Uri("http://feeds.feedburner.com/JonSkeetCodingBlog?format=xml")); 
    // it's chaining - one task starts executing after 
    // another, but it is still asynchronous 
} 
+0

これはすばらしいヒントです。本当にWebClientでの作業がはるかに簡単でした。ありがとう!! –

3

Jeremy Liknessには、ブログエントリタイトルCoroutines for Asynchronous Sequential Workflows using Reactive Extensions (Rx)があります。彼が答えようとしている質問は次のとおりです。

概念は単純です。非同期操作のセットを順番に実行することが往々にしてあります。サービスからリストをロードし、選択したアイテムをロードしてからアニメーションをトリガーする必要があります。これは、完了したイベントを連鎖させるかラムダ式を入れ子にすることによって行うことができますが、よりクリーンな方法がありますか?

+0

非常に興味深い。それは間違いなく便利です。私は他の答えが出てくるのを見るでしょう、特にタスクパラレルライブラリを使用している人。 – Jason

関連する問題