-1

「リアルタイム」に変換しようとしているシミュレーションがあります。「リアルタイム」と言うのは、必要に応じてパフォーマンスが低下しても問題ないためです (オブザーバー/クライアントの時間も遅くなります)。ただし、オブジェクトの数が少ない場合は、安定したフレーム レート (この場合は ~100 FPS) で実行されるようにパフォーマンスを制限したいと考えています。

sleep()Linux と Windows でそれぞれとを試しましたが、FPSが実際に目標の何分の 1 かに落ち込んでいるため、Sleep()十分に正確ではないようです。このシナリオは、ゲーム、特にオンライン ゲームでは一般的だと思いますが、この件に関して役立つ資料を見つけることができませんでした。フレーム制限の好ましい方法は何ですか? 指定された時間よりも多くの時間をあきらめないことを保証できるスリープ方法はありますか?

注: これを 2 つの異なるクラスター (Linux と Windows) で実行していますが、すべてのノードには組み込みのビデオしかありません。したがって、両方のプラットフォームで制限を実装する必要があり、ビデオカードベースであってはなりません (そのようなものがある場合でも)。また、1 つのスレッド/ノードのみに制限を実装する必要があります。これは、ノード間に既に同期があり、1 つのスレッドが適切に制限されている場合、他のノードも自動的に制限されるためです。

編集:現在のリミッターをどのように実装したかを示すいくつかの擬似コード:

while (ProcessControlMessages())
{
    uint64 tStart;
    SimulateFrame();
    uint64 newT =_context.GetTimeMs64();
    if (newT - tStart < DESIRED_FRAME_RATE_DURATION)
        this_thread::sleep_for(chrono::milliseconds(DESIRED_FRAME_RATE_DURATION - (newT - tStart)));
}

また、N フレームごとに制限を行うことができるかどうかも考えていました。ここで、N は目的のフレーム レートの一部です。試してみて、また報告します。

4

2 に答える 2

1

各フレームが完全なフレームになるのに十分な時間スリープしようとする代わりに、それらをスリープさせて平均化を試みます。グローバル/スレッド所有の時間カウントを保持します。各フレームには、現在の時刻ではなく、以前の希望の最早終了時刻から計算された「希望の最早終了時刻」があります。

tGoalEndTime = _context.GetTimeMS64() + DESIRED_FRAME_RATE_DURATION;
while (ProcessControlMessages())
{
    SimulateFrame();
    uint64 end =_context.GetTimeMs64();
    if (end < tGoalEndTime) {
        this_thread::sleep_for(chrono::milliseconds(tGoalEndTime - end)));
        tGoalEndTime += DESIRED_FRAME_RATE_DURATION;
    } else {
        tGoalEndTime = end; // we ran over, pretend we didn't and keep going
}

注:これを実行するsleep_forための変更の最小数を示したかったため、これはあなたの例を使用しています。 sleep_untilここでうまく機能します。

トリックは、スリープ時間が長すぎるフレームがあると、すぐに次の数フレームが急いで追いつくことです。

注: 最新の消費者向け OS では、2 ミリ秒 (100 fps で 20% のジッター) 以内のタイミングを取得できません。ほとんどの消費者向け OS のスレッドのクォンタムは約 100 ミリ秒であるため、スリープした瞬間に、自分の番になる前に複数のクォンタムでスリープする可能性があります。 sleep_until OS 固有の手法を使用してジッターを減らすことができますが、それに頼ることはできません。

于 2013-09-15T18:56:39.210 に答える