2017-01-10 12 views
2

私はc#async awaitの基本的な概念を理解するのに苦労しています。Async Foreach Loopを実行するC#asyncを待つ

基本的には、処理する必要があるオブジェクトのリストです。処理には、プロパティと文字列を繰り返してから、新しいオブジェクト(この場合はtrellocard)を作成し、最終的にトレコカード。

これは繰り返し時間がかかるため、非同期で複数のオブジェクトを処理したいと考えています。

私は複数のアプローチを試みましたが、基本的にはこのようなことをしたいと思います。 (以下の例では、処理を取り除き、system.threading.thread.sleep(200)を置いています。これは非同期メソッドではなく、tasks.delayを使用することができますが、私は複数のインスタンスで全体の方法を実行したい、すべての非同期メソッドを持っています。

private async Task<List<TrelloCard>> ProcessJobs(IQueryable<IGrouping<CardGrouping, Job>> jobs) 
    { 
     List<TrelloCard> cards = new List<TrelloCard>(); 

     foreach (var job in jobs.ToList()) 
     { 
      card = await ProcessCards(job, cards); // I would like to run multiple instances of the processing 
      cards.add(card); //Once each instance is finshed it adds it to the list 
     } 


    private async Task<TrelloCard> ProcessCards(Job job) 
    { 
     System.Threading.Thread.Sleep(2000); //Just for examples sake 

     return new TrelloCard(); 
    } 

答えて

1

私は待ってC#の非同期の基本的な概念を把握するのに苦労しています。

簡単な定義は次のようになり、 Async-Awaitは、複数のIOコールを作成するために使用できる.Netの並行処理であり、処理ではCompute操作用のスレッドを無駄にすることはありません。

その繰り返し処理
  1. :データベースへの呼び出し、Webサービス、ネットワーク呼び出し、ユースケースがある、あなたの現在のケースでは、現在のプロセスのスレッド

    を必要としないすべてが、IOファイルのようなTSプロパティと文字列を結合し、その後、最終的にはこれは、あなたがIOをやっているまでとしない限り、計算バインド操作であるように思わtrellocards

のリストを追加すること

  • 新しいオブジェクトを作成するには、私にはあなたがしているようですこの場合、メモリ内オブジェクトをトラバースするより良い選択は、次のようになります。

    1. Parallel.ForEach、あなたが与えられたメモリは、このように書き込み動作中に、特別にそれを破損、複数のスレッドがアクセスすることができたとして、競合状態に注意する必要があるものの、メモリ処理に並列化するために、そう、少なくともSystem.Collections.Concurrent名前空間、またはこれからConcurrentBagのような現在のコード使用スレッドセーフなコレクションでは、これまでの代わりList<TrelloCard>のユースケースに合わせて、またはあなたがThread safe list

    を以下検討することができる。また場合には、あなたの方法ではない、ということに注意してくださいデフォルトではAsyncですこれは、スレッドプールのスレッドを必要とするものの、時awaitに、Task.Runでそれらをラップするが、あなたのユースケースのためにAsync-Await

    Parallel.Foreachコードを使用して呼び出すことができます(私は直接交換をしています、に問題があるように思われますあなたのコードは、ProcessCards機能するので、ちょうどジョブオブジェクトを取りますが、あなたも)コンパイルエラーであるコレクションCardsを、渡している:

    private List<TrelloCard> ProcessJobs(IQueryable<IGrouping<CardGrouping, Job>> jobs) 
        { 
         ConcurrentBag<TrelloCard> cards = new ConcurrentBag<TrelloCard>(); 
    
         Parallel.ForEach(jobs.ToList(), (job) => 
         { 
          card = ProcessCards(job); // I would like to run multiple instances of the processing 
          cards.Add(card); //Once each instance is finshed it adds it to the list 
         }); 
    
          return cards.ToList(); 
        } 
    
        private TrelloCard ProcessCards(Job job) 
        { 
         return new TrelloCard(); 
        } 
    
  • +0

    ありがとうございました!驚くべきことに、ウェブの周りを見ていて、最初の3行が私に電球の瞬間を与えました。それは今私にとってははるかに理にかなっています。 – michael

    +0

    ようこそ、Webシナリオでは、Ajax呼び出しのようなもので、微妙な違いがあります.Net固有のものです。 –

    +0

    説明するための有権者の説明をお願いします –

    2

    あなたがそれらを並列に実行したい場合は、操作ごとに新しいタスクを起動できTask.WhenAllを使用してすべての完了を待ちます。

    private async Task<List<TrelloCard>> ProcessJobs(IQueryable<IGrouping<CardGrouping, Job>> jobs) 
    { 
        List<Task<TrelloCard>> tasks = new List<Task<TrelloCard>>(); 
    
        foreach (var job in jobs) 
        { 
         tasks.Add(ProcessCards(job)); 
        } 
    
        var results = await Task.WhenAll(tasks); 
    
        return results.ToList(); 
    } 
    
    
    private Task<TrelloCard> ProcessCards(Job job) 
    { 
        return Task.Run(() => 
        { 
         System.Threading.Thread.Sleep(2000); //Just for examples sake 
    
         return new TrelloCard(); 
        }); 
    } 
    
    +0

    ここで避けたいのは 'jobs.ToList()'だけです。リモート・オペレーションでなくなり、すべてのデータがプロセス・メモリーにロードされるため、計算バウンド・オペレーションはIOバウンド・オペレーションよりも適切です。実際にはAsync-Awaitの目的を打ち負かしてしまうでしょう。 –

    +0

    @MrinalKambojはいWPF/WinFormsでUIをブロックしている場合は、async/awaitを使ってこのコード(計算上の境界)を書く唯一の理由があります。 ASP.NETアプリケーションでは、集中的な作業ではasync/awaitを使用しないでください。 –

    +0

    WPFでもそうでない場合は、 'Threadpool'スレッドで呼び出しを開始することができます。いつでも実行する必要がある' Ui control 'を更新するまで、 'Async-Await'は必要ありません'Uiスレッドコンテキスト'では、例外があります(スレッドがないため、Async-Awaitを使用して簡単に達成できます)。理想的には、集約的な作業を行うアプリケーションロジックは、IOコール用にのみ設計されたAsync-Awaitを使用する必要があります。 –

    1

    jobs.ToList()だけでメモリを無駄にしています。それは既にIEnumerableですので、foreachで使用できます。

    ProcessCardsはコンパイルされません。あなたは今、あなたはProcessJobs

    • にしたい、この

      private Task<TrelloCard> ProcessCards(Job job) 
          { 
           return Task.Run(() => 
           { 
            System.Threading.Thread.Sleep(2000); //Just for examples sake 
      
            return new TrelloCard(); 
           }); 
          } 
      

      のようなものを必要とするすべてのタスクが

    • リターン・TrelloCard

      のシーケンスを完了するため、各ジョブ
    • 待機用ProcessCardsタスクを作成します
      private async Task<List<TrelloCard>> ProcessJobs(IQueryable<IGrouping<CardGrouping, Job>> jobs) 
      { 
          return await Task.WhenAll(jobs.Select(ProcessCards)); 
      } 
      
  • +0

    +1、以前のコメントの1つでは、 'Async-Await'の使用法では、' jobs.ToList() 'を使わないことが重要であることを指摘しています。非同期処理の代わりに単純な並列処理 –

    関連する問題