3

あいまいなスレッド タイトルで申し訳ありません。私の質問を簡潔に説明するのは難しいです。

次のように定義された多数のオブジェクト(数千)のコレクションがあります...

public class Item
{
    public int ID;
    public float A;
    public float B;
    public float C;
    public float D;
    public float E;
    public float F;
    public float G;
}

これらのフロート フィールドのそれぞれに乗数が与えられた場合、大きなコレクションのどのアイテムが、それらの浮動小数点数に乗数を掛けた最大の合計を持っているかを見つける最速の方法は何ですか?

たとえば、私は現在次のようなものを持っています...

public Item FindLargest(float aMult, float bMult, float cMult, float dMult, float eMult, float fMult, float gMult)
{
    Item largest = null;
    float largestTotal = 0f;
    foreach(Item item in ItemsCollection)
    {
        float total = item.A * aMult + 
                      item.B * bMult + 
                      item.C * cMult + 
                      item.D * dMult + 
                      item.E * eMult + 
                      item.F * fMult + 
                      item.G * gMult;
        if (total > largestTotal)
        {
            largest = item;
            largestTotal = total;
        }
    }
    return largest;
}

これのパフォーマンスが不足しているため、FindLargest 呼び出しがはるかに高速になるように、事前にデータを再構築するために何かできることはないかと考えています。私はしばらくの間このようにしてきましたが、パフォーマンスは良好で、ItemsCollection には 40 ~ 50 個のアイテムがありましたが、アプリケーションの別の部分の設計が変更され、副産物として処理する必要があります。はるかに大きなデータ セット (~50ish ではなく ~2000ish) であるため、これをさらに最適化することに興味があります。誰でも提供できる助けをありがとう!

編集: 最初にこれに言及する必要がありました: これを呼び出しているものは既に高度に並列化されているという点で、既にこれを並列化しています。そして、これを呼び出しているのは、実際には、多くの異なるパラメーターを使用して、非常に迅速に何度も呼び出していることです。アプリで開いているドキュメントの値が変更されるたびに、これを約 100 回呼び出す必要があり、「応答性が高い」と感じるはずです (すでに複数のバックグラウンド スレッドですべての計算を行っているため、UI のロックアップを意味するものではありません)。 .

編集2:受け入れられた回答で私のコメントを参照してください。

4

4 に答える 4

5

ここでの機能に問題はないと思います。コレクション内の500,000アイテムで関数を完了するのに、0.1秒もかかりません。

この関数を呼び出すコードの部分を最適化する方法を見つけたいと思うかもしれません。そのレベルでPLINQを使用すると、より良い結果が得られるはずです。

于 2011-03-24T03:38:09.917 に答える
5

1 つのオプションは、PLINQを使用して複数のコアを利用することです。

        var result = (from item in ItemsCollection
                      let total = item.A * aMult + 
                                  item.B * bMult + 
                                  item.C * cMult + 
                                  item.D * dMult + 
                                  item.E * eMult + 
                                  item.F * fMult + 
                                  item.G * gMult
                      select new {item, total}).AsParallel().Max(i => i.total);
于 2011-03-24T03:03:37.227 に答える
1

上記の乗算を行う場合は、Parallel.ForEachの使用を検討してください。Item.IDとその合計を保持するディクショナリとしてルックアップテーブルを実装することを検討することもできます。したがって、乗算が完了したら、LINQを使用して、合計が最大のアイテムを並べ替えて抽出できます。何かのようなもの:

var sortedItems = from item in ItemsTotalsDictionary orderby item.Value descending select item.Key;

于 2011-03-24T03:38:27.600 に答える
1

データセットを 6 つの連続する範囲に分割します。最大値を計算するために非同期に起動される別のスレッドに各範囲を割り当てます。すべてのスレッドが完了すると、各範囲から 1 つずつ、6 つの異なるアイテムが得られます。6 を反復して、データセット全体で最大のものを見つけます。

あなたができるさらなる最適化があります。

自分で .NET スレッドを起動する代わりに、Microsoft の PLINQ ライブラリを使用して簡単にコーディングできます。

于 2011-03-24T03:17:14.040 に答える