3

forループ内では、車両の情報を取得して処理することにより、シミュレーションステップベースの交通シミュレータSUMOを制御しています。プログラムが「リアルタイム」(1シミュレーションステップ= 1秒)でシミュレートすることを確認するために、処理フェーズの後、次のタイムステップが始まるまでプログラムをスリープさせたいと思います。より良い結果を得るために、最初に取得した参照タイムスタンプに基づいてタイムスタンプを計算しています。

ループは次のようになります。

    System.out.println("start of traffic simulation ...");

    for (int i = 0; i < stepCount; i++)
    {
        System.out.println("step: " + i);

        // set before timeStamp
        beforeTimeStamp = System.currentTimeMillis();

        if (firstStep)
        {
            // get reference timeStamp
            referenceTimeStamp = beforeTimeStamp;
            firstStep = false;
        }
        else
        {
            // get next vehicleVector
            vehicleVector = masterControl.traCIclient.simulateStep();
        }

        // process vehicleVector

        // set after timeStamp
        afterTimeStamp = System.currentTimeMillis();

        processingTime = afterTimeStamp - beforeTimeStamp;

        // calculate sleepTime
        sleepTime = referenceTimeStamp + ((i + 1) * 1000) - afterTimeStamp;

       // sleep for sleepTime ms
       Thread.sleep(sleepTime);
    }

    System.out.println("end of traffic simulation ..."); 

いくつかの変数の出力は次のとおりです。

ステップ:0                                                                                                         
beforeTimeStamp 1252317242565                                                                                   
基準時間:1252317242565                                                                                   
処理時間:394                                                                                            
テスト時間:1252317243565                                                                                        
afterTimeStamp 1252317242959                                                                                    
sleepTime:606                                                                                                  
ステップ1                                                                                                         
beforeTimeStamp 1252317242961                                                                                   
処理時間:665                                                                                            
テスト時間:1252317244565                                                                                        
afterTimeStamp 1252317243626                                                                                    
sleepTime:939(検査済み:1000-665 = 335)                                                                                                  

ご覧のとおり、スリープ時間は最初のシミュレーションステップでのみ正しいです。ここで何がうまくいかないのかわかりません。誰かアイデアがありますか?

BR、

マーカス

4

5 に答える 5

10

Java はスレッド スケジューリングに関して絶対的な保証を提供しないため、標準 Java を使用して正確な時間スリープすることはできません。Java は、OS によって割り当てられた CPU 時間の影響を受け、プログラムは予測不能なガベージ コレクションの一時停止の影響を受けます。

予測可能な実行が必要な場合は、 Java のリアルタイム仕様を確認する必要があります。ここでは明らかにやり過ぎです!

パッケージで を使用ScheduledExecutorServiceして、java.util.concurrentタスクを定期的に実行できます (一定期間スリープするか、特定の速度で実行するかのいずれかによって)。使用法:

import static java.util.concurrent.*

Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(task, 0, 1, TimeUnit.SECONDS)

しかし、これは正確ではありません(JavaDoc を参照):

ただし、ネットワーク時間同期プロトコル、クロック ドリフト、またはその他の要因により、相対的な遅延の有効期限が、タスクが有効になった現在の日付と一致する必要はないことに注意してください。

(私のものを強調)

于 2009-09-07T10:07:19.553 に答える
4

なぜ眠らないの1000 - processingTimeですか?それが最も正しい答えに近づくでしょう。

最初のステップでのみ正しいため、ソリューションは最初のステップでのみ機能します。で各ステップの処理を開始すると想定していますがreferenceTime + (step * 1000)、オーバーヘッド (スレッドのスリープ、印刷、ガベージ コレクション) は考慮していません。referenceTimeStamp + ((i + 1) * 1000) - beforeTimeStamp 私が何を意味するかを見るために印刷し てください

于 2009-09-07T10:08:21.503 に答える
3

Java 5 以降の Java には、単純な標準ソリューションがあります。

ScheduledExecutorServiceを見てください。

次のようになります。

        ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
        service.scheduleAtFixedRate(new MyCode(), 0, 1, TimeUnit.SECONDS);

MyCode クラスは実行可能なインターフェイスを実装し、1 秒に 1 回実行されます。

これはリアルタイムの保証ではありませんが、あなたの場合には十分なはずです。

于 2009-09-07T10:18:33.203 に答える
2

他の人が強調しているように、処理時間は 1000 です。

Java SE がリアルタイム プラットフォームを提供しない (そのため、精度が得られない) という事実を無視して、Timerクラス、特にTimer.scheduleAtFixedRate()を調べます。定期的にタスクをスケジューリングする。

于 2009-09-07T10:18:22.220 に答える
0

出力が同じプログラムからのものであると確信していますか? インラインで強調表示されている不一致を確認してください。

step:   0                                                                                                         
beforeTimeStamp 1252317242565                                                                                   
reference time: 1252317242565                                                                                   
processing time: 394                                                                                            
test time: 1252317243565                                                                                        
afterTimeStamp 1252317242959                                                                                    
sleepTime: 606 #### It didn't sleep this long at all
step: 1                                                                                                         
beforeTimeStamp 1252317242961 #### This is only 2ms from last afteTimeStamp                                                                                 
processing time: 665                                                                                            
test time: 1252317244565                                                                                        
afterTimeStamp 1252317243626                                                                                    
sleepTime: 939 (exspected: 1000 - 665 = 335)  #### This is to make up the deficit from last sleep                                                                                                

こぶし睡眠には 604 (606-2) の赤字がありました。したがって、939 (335 + 604) が 2 番目のループの正しいスリープ時間です。

Java のスリープは正確ではありませんが、それほど遠くないはずです。デバッガーでプログラムを中断するか、コードが出力と一致しないと思います。

于 2009-09-07T11:10:28.227 に答える