2017-02-17 6 views
1

私はシングルスレッドコールParallel.Foreachにおける方法およびスレッドセーフリストに結果を保存

foreach (var meetingRoom in meetingRooms) 
{ 
      try 
      { 
       var res = calendarService.GetEvents(meetingRoom.Email, startUtc, endUtc, lightweight, limit); 
       result.AddRange(res); 
      } 
      catch (Exception ex) 
      { 
       Log.Error(ex); 
      } 
} 

で罰金を実行しているこのコードを持っていますが、問題はmeetingRoomsリストは、40件の以上の000エントリが含まれています。私はParallel.Foreachにアプローチしようとしています - これはI'veがこれまでに得たものである:

Parallel.ForEach(meetingRooms,() => 0,(meetingRoom) => 
     { 
      var res = calendarService.GetEvents(meetingRoom.Email, startUtc, endUtc, lightweight, limit); 

     } 
     , 
     finalResult => 
     { 
      lock (result) 
      { 
       result.Add(finalResult); 
      } 
     }); 

私は第四パラメータlocalFinallyがどのように動作するかを理解して運を持っていません。

resultおよびmeetingRoomsは、異なるデータ型のリストです。

EDIT:回答の一つが示すよう

I'veはPLINQソリューションを実装しました。動作しているようですが、Exchange Webサービス(EWS)ライブラリは、そのメソッドの1つを並列呼び出しするために実装されていません。取得とエラー "ユニークなキーではありません!"マイクロソフトのコードによってスローされます。

+0

本当にここでは問題はありません - 私は "localFinally"のpaterを見ません..特に問題は何ですか – BugFinder

+0

これはどんなコンテキストですか? ASP.NET、コンソール、WPF、Windowsフォーム? –

+0

サンプルは 'result.Add()'と 'result.AddRange()'の使用に一貫性があります。 –

答えて

3

PLinqを使用できます。

result = meetingRooms 
    .AsParallel() 
    .Select(meetingRoom => calendarService.GetEvents(meetingRoom.Email, startUtc, endUtc, lightweight, limit)) 
    .ToList(); 

それでもParallel.ForEachを(使用する)、localFinallyとのオーバーロードはそれほど有用ではありません。基本を使用します。

Parallel.ForEach(meetingRooms, meetingRoom => 
    { 
     var res = calendarService.GetEvents(meetingRoom.Email, ...); 

     lock (result) // only OK when you don't lock on it anywhere else 
     { 
      result.Add(res); 
     } 
    }); 
+1

ローカル状態のForEachバージョンが役に立たないと思う理由がわかりません。各パーティションがロックせずにアクセスできるローカル状態を持つように使用されていませんか? – Dirk

+0

なぜあなたはそれが役に立つと思いますか?中間結果が非常に小さい場合に使用できます。実質的な何かをGetEvents()が大幅に違いがありません –

+1

40000会議室があると、あなたのバージョンは、ループの各反復のロックステートメントを呼び出すでしょう。ローカル状態のバージョンはパーティションごとに1回だけロックされますが、これはかなり少なくなります。 GetEventsへの呼び出しにロックを取得して解放するよりもはるかに時間がかかるが、それは発見するOPまでである。 – Dirk

0

ます。また、結果を保存し、ロックを避けるためにConcurrentBag(またはConcurrentQueueまたはConcurrentDictionary)を使用することができます。

+2

*並行バッグではなく、高速スレッド*ローカル*ストレージ用です。 –

+0

アプリケーションのニーズによって異なります。この場合、項目の追加はConcurrentBagで高速になり、(同じスレッドからの)それらの読み取りは内部ロックを使用します。 – bcl

+0

@PanagiotisKanavos - "並行バッグはスレッドローカルストレージ用です"ハァッ?それには引用が必要です。 –

関連する問題