2012-04-17 3 views
4

私はforeachループを実行しています。私は並列関数を探しています。並列プログラミングを使用するために次のコードを変換することは可能ですか?parallel.ForEachを使用して別の関数を呼び出すことはできますか?

int result ; 
int counter; 
foreach(DataRow dr in ds.Tables[0].Rows) { 
    switch(dr["Gender"].ToString()) { 
     case "Male": 
      result = functionMale(dr["Gender"].ToString()); 
      counter += result; 
      break; 
     case "Female": 
      result = functionFemale(dr["Gender"].ToString()); 
      counter += result; 
      break; 
     default: 
      result = functionUnkown(dr["Gender"].ToString()); 
      counter += result; 
      break; 
    } 
} 

私が調べたことに基づいて、これまでのところ以下のものしかありません。

Parallel.ForEach(ds.Tables[0].AsEnumerable(), dr => { 
    var result = functionMale(dr["Gender"].ToString(); 
}); 

ありがとう

+0

ここでは、C#の並列環境での集約へのリンクです。http://msdn.microsoft.com/en-us/library/ff963547.aspx – Servy

答えて

0

確かに、それは可能です。 Parallel.ForEachは、このインスタンス(スレッド以外)で、特定の魔法のいずれかの種類をやってイマイチなので、それだけで次のようになります。さらには可換であるため、

ds.Tables[0].Rows.AsEnumerable().AsParallel().Sum(x => 
    { 
     DataRow dr = x as DataRow; 

     switch(dr["Gender"].ToString()) 
     { 
      case "Male": 
      // Stuff 
      case "Female"; 
      // Stuff 
      default: 
      // Stuff 
     } 

     return counter; 
    }); 

これは、機能のすべての値を集計する必要があります。

+1

これらの依存関係はあります。彼はデータを集約しています。 – Servy

+0

カウンターコードで更新されました。私の悪い、私は集計を見ていない。 – Tejs

3

あなたは、より機能的なスタイルで、このような何かを試みることができる:

var counter = 
    ds.Tables[0].AsEnumerable() 
    .AsParallel() 
    .Select(dr => { 
     var gender = dr["Gender"].ToString(); 

     switch(gender) 
     { 
      case "Male": 
       return functionMale(gender); 
      case "Female": 
       return functionFemale(gender); 
      default: 
       return functionUnkown(gender); 
     } 
    }) 
    .Sum(); 
+0

リスト内のすべてのレコードを最初に(内部的に)選択してから、合計関数を選択するのが好きですか? – Pankaj

+1

はい - しかしselectは "それが行く"と呼ばれています - したがって、おそらくsixlettervariablesから上記の他の答えと同じパフォーマンスプロファイルを持つつもりです –

5

あなたはAsParallelSumを使用することができます。

Func<string, int> calculateGender = 
    gender => 
    { 
     // nb: I don't know why you pass the gender to the method, but 
     // I've left your intent as-is 
     switch (gender) 
     { 
      case "Male": return functionMale(gender); 
      case "Female": return functionFemale(gender); 
      default:  return functionUnknown(gender); 
     } 
    }; 

int counter = ds.Tables[0].AsEnumerable() 
          .AsParallel() 
          .Sum(dr => calculateGender(dr["Gender"].ToString())); 
+0

私はちょっと混乱しています。 @Daveは同じことをやっている。それはより速いですか? – Pankaj

+0

@PankajGarg:わかりませんが、実際には違いはありません。 – user7116

+0

おそらくまったく同じで、背後では同じです。 –

0

PLINQのアプローチは非常に簡単ですが、ちょうど丸めますここで答えはParallel.ForEachでこれを行う方法です。

int counter = 0; 
Parallel.ForEach(ds.Tables[0].AsEnumerable(), 
() => /* subtotal initializer */ 
    { 
    return 0; 
    }, 
    (dr, state, subtotal) => /* loop body */ 
    { 
    switch(dr["Gender"].ToString()) 
    { 
     case "Male": 
      subtotal += functionMale(dr["Gender"].ToString()); 
      break; 
     case "Female": 
      subtotal += functionFemale(dr["Gender"].ToString()); 
      break; 
     default: 
      subtotal += functionUnkown(dr["Gender"].ToString()); 
      break; 
    } 
    }, 
    subtotal => /* subtotal accumulator */ 
    { 
    Interlocked.Add(ref counter, subtotal); 
    }); 

これはどのように動作するかです。最初のラムダ式は、各従業員のローカル小計ビンを初期化して、TPLがアウトドアするようにします。 2番目のラムダ式は、コレクション内のアイテムごとに1回実行され、ローカル小計ビンを更新します。 3番目のラムダ式はローカル小計ビンを最終的な合計に結合します。

Parallel.ForEachAsParallelを集約で使用することの1つの興味深い違いは、小計が最終価値に累積される方法にあります。 Parallel.ForEachこの操作はワーカースレッド上で行われるため、スレッドセーフな操作Interlocked.Addが必要です。 AsParallelは同じ分割戦略を使用しますが、呼び出し側スレッドに小計を累積します。

関連する問題