4

実行する 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();
});

何か案は?ありがとう

4

4 に答える 4

5

AsParallelとを使用できますSum

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()));
于 2012-04-17T15:27:41.677 に答える
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();
于 2012-04-17T15:26:58.010 に答える
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.ForEach集計を使用する場合と使用する場合の興味深い違いの 1 つAsParallelは、小計が最終値に累積される方法にあります。Parallel.ForEachこの操作はワーカー スレッドで実行されるため、スレッド セーフな操作が必要になりますInterlocked.AddAsParallel同じパーティション戦略を使用しますが、呼び出し元のスレッドで小計を累積します。

于 2012-04-17T18:04:02.727 に答える
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;
  });

加算は交換可能であるため、これは関数のすべての値を集約する必要があります。

于 2012-04-17T15:24:02.273 に答える