1

これは、バッファリングされたソースからデータを取得し、それを送信して処理するフラグメントです。キューが空の場合、get() は null を返し、プロセス メソッドは null を受け取って何もしません。これをコーディングする最も最適な方法は何ですか?

something a; // any legal C++ return type...
aQueueOfSomethings g;

while (true) { 
    a=g.get();
    process(a);
}

get() 経由で到着する値を予測する方法はありません。それらはそのままであり、可能な限り迅速にキューから取り出して process() に渡す必要があります。

「a」という名前の明示的なローカル変数をスキップして、ループを 1 つのライナーにすると、無駄な労力はあまり見られません。

    process(g.get());

g.get() の暗黙の戻り値にはまだスペースが割り当てられており、コンストラクターの呼び出しなどが含まれる可能性があります。

返されたものにサイズや複雑さがある場合は、そのコピーではなくそれへのポインターを持ち、値によるコピーではなくそのポインターを渡す方がよいでしょう...だから私は

something *a;

    g.get(a);
    process(a);

それよりも

 something a;

    a=g.get();
    process(a);

2 行バージョンと 1 行バージョンを試して、100,000,000 回ループするテスト ケースを c++ で作成しました。

a が 4 つの整数と 2 つの浮動小数点数を持つオブジェクトであり、process() メソッドがそれらすべてに触れる場合、実際には 2 行のソリューションの方が高速です! オブジェクトが単一の int の場合、1 行バージョンの方が高速です。オブジェクトが複雑で、process() メソッドが 1 つの値に触れるだけの場合は、1 行バージョンの方が高速です。

私にとって最も興味深いのは、g++ コンパイラ、Mac OS X 10.5.8 を使用して、-O 第 1 レベルの最適化スイッチを使用すると、1 行バージョンと 2 行バージョンの両方で同じ、はるかに高速な操作が得られることです。

コンパイラに最適化させ、両方のメソッドを 1 行で明示的な中間変数を使用せず、参照渡しでコピーを作成しないようにする以外に、一般的に実行を高速化するものはありますか? 明らかな何かが欠けているように感じます。

4

4 に答える 4

3

これは無駄な最適化の最たるケースだと思います

(バッファリングするものを取得していて、それをビット最適化したいですか? )

また、コンパイラは両方の方法をまったく同じコードにコンパイルし、(ほとんどの状況で) 戻り値の最適化末尾呼び出しの最適化を完全に実行できます。

queue_class::get() のインライン化の可能性と組み合わせると、問題は完全にMOOTのようです

于 2011-04-28T08:50:27.613 に答える
3

あなたは自分の仕事でコンパイラを打ち負かそうとしていると思います。

パフォーマンスの問題を経験したことがありますか? そうでない場合は、時期尚早の最適化に頼ったり、変な最適化でコードを雑然とさせたりするのではなく、維持できる読み取り可能なコード (持っているように見える) を作成することに集中することができます。

于 2011-04-28T08:52:43.607 に答える
2

このコードの問題は、あなたが何をしたかではなく、スピンしなければならないということです -あなたのコンピュータが実行している他のタスクが使用した可能性のあるCPU サイクルを浪費しています - やるべき仕事がない場合でも.

このような態度をとるプログラムが多数ある場合 (それらはコンピューターの王様であり、CPU 全体を占有する)、すべてが完全に遅くなります。コードをこのように動作させることは、非常に抜本的な決定です。

可能であれば、モデル全体を変更して、利用可能なデータが増えたときに何らかのコールバック/シグナル/イベントを取得できるようにします。

于 2011-04-28T08:51:00.920 に答える
1

コンパイラに最適化させるべきなのはあなたの言うとおりですが、これを実行しても安全であることがわかっている場合は、次のようにします。

while (true) { 
    a=g.get();
    b=g.get();
    c=g.get();
    d=g.get();
    process(a);
    process(b);
    process(c);
    process(d);
}

それは物事をより速くするかもしれません。

または、さらに極端な場合、戻り値の型 (またはそれへのポインター) の配列全体を準備してから、それらを処理するためにループします。process() と get() の両方が大量のコードを使用する場合、これを行うと、関数が呼び出されるたびに追加のキャッシュからフェッチされるのではなく、すべてのコードが即時キャッシュに保持される可能性があります。

コンパイラは、関数呼び出しの順序を変更しても安全であることをおそらく認識していないため、この最適化を行うことができません。

于 2011-04-28T08:50:50.940 に答える