2

次の単純なコード パターンを検討してください。

foreach(Item item in itemList)
{
   if(item.Foo)
   {
      DoStuff(item);
   }
}

Parallel Extensions(PE) を使用して並列化したい場合は、次のように for ループ構造を単純に置き換えることができます。

Parallel.ForEach(itemList, delegate(Item item)
{
   if(item.Foo)
   {
      DoStuff(item);
   }
});

ただし、PE は、Foo が false であることが判明したアイテムのスレッドに作業を割り当てる不要な作業を実行します。したがって、ここでは中間ラッパー/フィルタリング IEnumerable が合理的なアプローチであると考えていました。同意しますか?もしそうなら、これを達成する最も簡単な方法は何ですか? (ところで、私は現在 C#2 を使用しているので、ラムダ式などを使用しない例が少なくとも 1 つあればありがたいです。)

4

3 に答える 3

4

PE for .NET 2 でのパーティショニングがどのように機能するのかよくわからないので、ここで言うのは難しいです。各要素が個別の作業項目にプッシュされる場合 (これはかなり貧弱な分割戦略です)、事前にフィルタリングすることは非常に理にかなっています。

ただし、item.Fooたまたまコストが高かった場合 (プロパティであることを考えると、これは予想できませんが、いつでも可能です)、並列化できるようにすると有利になる可能性があります。

さらに、.NET 4 では、TPL で使用されるパーティショニング戦略がこれをかなりうまく処理します。これは、さまざまなレベルの作業を伴う状況を処理するように特別に設計されています。「チャンク」に分割するため、1 つのアイテムが1 つのスレッドに送信されるのではなく、スレッドに一連のアイテムが割り当てられ、それが一括して処理されます。falseになる頻度によっては、item.Foo(TPL を使用して) 並列化する方が、事前にフィルター処理するよりも高速になる可能性があります。

于 2010-02-02T23:06:28.443 に答える
1

これを実装する場合は、foreachを呼び出す前に、リストをフィルタリングするだけです。

var actionableResults = from x in ItemList WHERE x.Foo select x;

これにより、リストをフィルタリングして、操作可能なアイテムを取得します。

注:これは時期尚早の最適化である可能性があり、パフォーマンスに大きな違いをもたらすことはできません。

于 2010-02-02T22:50:30.903 に答える
1

すべての要因は、次の 1 行に絞り込まれます。

Parallel.ForEach(itemList.Where(i => i.Foo), DoStuff);

しかし、別の投稿へのコメントを読むと、まだ .Net 2.0 を使用していることがわかります。そのため、コンパイラをこっそり通り抜けるのは少し難しいかもしれません。

.Net 2.0 の場合、次のようにできると思います (メソッド名をデリゲートとして渡しても機能するかどうかは少しわかりませんが、機能すると思います)。

public IEnumerable<T> Where(IEnumerable<T> source, Predicate<T> predicate)
{
   foreach(T item in source)
       if (predicate(item))
          yield return item;
}

public bool HasFoo(Item item) { return item.Foo; }

Parallel.ForEach(Where(itemList, HasFoo), DoStuff);
于 2010-02-02T23:01:29.973 に答える