2

私はマルチスレッド システムを使用しており、x個のスレッドが同時にネットワークにパケットを送信しています。

これはすべてうまくいきますが、特定のレートでパケットを送信するために速度を制限したいスレッドもあります。

そのため、パケット インジェクション ループにスリープを入れると、小さな速度 (1 Mbps から約 70 Mbps まで) でスレッドが適切に遅くなりますが、1 Gbps に制限したい場合は、スリープではその速度に到達できません。所定の位置に。すべてのスレッドからスリープを削除すると、それぞれ約 2 Gbps で注入できるため、その速度に到達できることがわかりました。

テストとして、私は自分の睡眠を

usleep(0);

これにより、速度が再び最大速度に戻るはずだと信じていましたが、まだ制限されたままです (最大速度の約 1/20 にしか達しません)。したがって、私の現在の唯一の説明は、sleep(0) の場合でもスレッドが譲歩するため、どのスレッドも十分な実行時間を取得していないということです。

長い説明で申し訳ありませんが、そのようなパフォーマンスの低下を引き起こさずにスレッドをスリープ状態にするより良い方法はありますか?

usleep と nanosleep を試しましたが、両方で同じ結果が得られました。すべてのテストで同じ設定、つまりスレッド数

システム: CentOS、pthreads、g++ 4.4.6

4

4 に答える 4

2

単純に反復ごとにではなく、注入されたパケットsleepごとに呼び出しを追加することを検討してください。nそうすれば、注入されるすべてのパケットでスレッド切り替えのペナルティが発生することはなく、実行されるスリープの量をかなりきめ細かく制御できます。

于 2013-02-21T09:17:53.570 に答える
1

関数呼び出し自体が速度を低下させている可能性があります (関数呼び出しのセットアップと破棄のため、または呼び出し内の何かが他のことを行っているため、速度が低下している可能性があります)。

次のような行を検討することをお勧めします。

if (delay > 0) usleep (delay);

遅延が必要ない場合は、関数がまったく呼び出されないようにします。

それを次のようにカプセル化することもできます。

#define usleepIfNonZero(n) { if (n > 0) usleep (n); }

もちろん、通常の警告がマクロ パラメータに適用されます (次のようなものを渡さないでください。そうしないx++と、2 回インクリメントされます)。


または、計算に使用するパケット数とベース時間を維持し、平均速度を算出します。例えば:

#define PACKETS_PER_SEC 25

baseTime = now() - 1; // prevent divide by zero later on 
packetCount = 0;
while (1) {
    sendPacket (nextPacket());
    packetCount++;
    secondCount = now() - baseTime;
    while (packetCount / secondCount > PACKETS_PER_SEC) {
        sleep (1);
        secondCount = now() - baseTime;
    }
}

これにより、1 秒あたりのパケット数が 25 に達するポイントに自動的に収束しますが、もちろん処理によってはフル スピードに到達できない場合があります。

于 2013-02-21T09:16:25.983 に答える
0

あなたは、「私の現在の唯一の説明は、sleep(0) の場合でもスレッドが譲歩するため、どのスレッドも十分な実行時間を取得していないということです」と述べました。

http://pubs.opengroup.org/onlinepubs/7908799/xsh/usleep.htmlによると、 usleep (...) が 0 を取得しても影響がないため、0 を渡してもスレッド コンテキストの切り替えは発生しません。

usleep(0); を確認しましたか? 本当に問題が発生していて、この呼び出しをコメントアウトすると、すべてが期待どおりに機能しますか?

于 2013-02-21T09:34:06.707 に答える
0

スロットリングを行うために、このようにスリープに依存しないでください。リアルタイム システムではありません。

代わりに、X データ/時間単位を送信したい場所に X データのバーストを送信します。ここで、時間単位はおそらくミリ秒などです。次に、各バーストを送信した後、必要な平均帯域幅に到達するためにスリープする必要がある時間を計算し、その時間だけスリープします。最後のバーストでこの計算を行うのではなく、各バーストの開始時間を高精度のタイミングで記録し、より大きな一連のバースト、たとえば最後の 100 バーストなどで償却を計算します。このようにして、コンテキストの切り替え、システム コール、メインの送信ループの外側にあるもの、および実行中のプロセスに戻る際の遅延のオーバーヘッドを平均化します。

usleep(x) (x != 0) を実行すると、実行キューのどこかに追加されるだけで、非リアルタイム システムで再び実行中のプロセスになる速度は保証されません。したがって、オーバーヘッドのこのような差異を時間の経過とともに償却する必要があります。

于 2013-02-21T09:45:49.937 に答える