2013-07-12 17 views
11

最近、私はasync/await呼び出しのスレッドを抑制する例を紹介しました。私のマシン上でコードを分析して遊んだ後、私は同じことをするためのやや異なる方法を思いついた。私が不確かなことは、ボンネットの下で起こっていることはほぼ同じか、注目に値する微妙な違いがあるのでしょうか?ここでasync/awaitを使用したセマフォースレッドのスロットル

は、元の例に基づいてコードです:

private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5); 

public async Task CallThrottledTasks() 
{ 
    var tasks = new List<Task>(); 

    for (int count = 1; count <= 20; count++) 
    { 
     await _semaphore.WaitAsync(); 

     tasks.Add(Task.Run(async() => 
      { 
       try 
       { 
        int result = await LongRunningTask(); 
        Debug.Print(result.ToString()); 
       } 
       finally 
       { 
        _semaphore.Release(); 
       } 
      })); 
    } 

    await Task.WhenAll(tasks); 

    Debug.Print("Finished CallThrottledTasks"); 
} 

そしてここでは、同じコードが私の感想です:

private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5); 

public async Task CallThrottledTasks() 
{ 
    var tasks = new List<Task>(); 

    for (int count = 1; count <= 20; count++) 
    { 
     await _semaphore.WaitAsync(); 

     tasks.Add(LongRunningTask().ContinueWith(t => 
     { 
      try 
      { 
       int result = t.Result; 
       Debug.Print(result.ToString()); 
      } 
      finally 
      { 
       _semaphore.Release(); 
      } 
     })); 
    } 

    await Task.WhenAll(tasks); 

    Debug.Print("Finished CallThrottledTasks"); 
} 

私は遠く離れて、おそらくんだけど、それはタスクのように思えます。 Runアプローチでは、LongRunningTask()を実行するタスクを作成してから、結果を出力するための継続を追加しますが、私のアプローチはTask.Runによって作成されたタスクをバイパスし、その結果として少しリーンです。これは正確なのですか?

答えて

12

あまりリーンではありませんが、ほんの少しです。通常、awaitはクリーナーであり、より多くのasync-フレンドリーなデフォルトセマンティクスを持っているので、をasyncコードで避けます。まず開発者の時間を最適化し、次に他の考慮事項を最適化します。

コードでは、セマンティクスがわずかに変更されます。元のコードでは、LongRunningTaskがスレッドプールコンテキストから実行され、コードではCallThrottledTasksコンテキストが実行されます。また、コードはLongRunningTaskの例外を完全に伝播しません。 Task<T>.ResultAggregateExceptionに例外をラップし、awaitはラッピングを行いません。

+0

ありがとうございます。これは私が探しているものです。実装上の副作用がクラックを通ることです。 async-awaitでそれがたくさんあるような気がします。私は例外がどのように扱われるかについていくつかの足の仕事をします。私はTPLからのAggregateExceptionに精通していますが、これに十分な手を携えていません。 – AFM

+2

実際には、TPLからの残り物のケースがあります - 非常にまれに - 非同期で便利ですが、たいてい途中で取得するよりも頻繁になります。たとえば、 'Task'コンストラクタ、' Start'、 'Wait'、' Result'、 'ContinueWith'、' WaitAll'、および 'WaitAny'は* parallel *(非同期*ではない)プログラミング用です。あなたがしていることを本当に分かっていない限り、「非同期」の世界です。 –