2009-09-07 67 views
3

在for循環中我通過檢索和處理車輛信息來控制基於模擬步驟的交通模擬器SUMO。爲了確保我的程序在「實時」模擬(1個模擬步驟= 1秒),我想在處理階段之後讓程序進入睡眠狀態,直到下一個時間步驟開始。爲了獲得更好的結果,我正在計算基於最初採用的參考時間戳的時間戳。java中的時間同步

循環是這樣的:

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 ..."); 

這裏的一些變量的輸出:

 
step: 0                           
beforeTimeStamp 1252317242565                     
reference time: 1252317242565                     
processing time: 394                        
test time: 1252317243565                       
afterTimeStamp 1252317242959                      
sleepTime: 606                         
step: 1                           
beforeTimeStamp 1252317242961                     
processing time: 665                        
test time: 1252317244565                       
afterTimeStamp 1252317243626                      
sleepTime: 939 (exspected: 1000 - 665 = 335)                         

正如你所看到的睡眠時間僅在第一模擬步驟正確。我不知道這裏可能會出現什麼問題。有人有想法嗎?

BR,

馬庫斯

回答

4

爲什麼不睡覺1000 - processingTime?這將是最接近你的正確答案。

您的解決方案僅適用於第一步,因爲它僅適用於第一步。您假定您將開始處理referenceTime + (step * 1000)的每個步驟,但是您沒有考慮開銷(線程休眠,打印,垃圾回收)。 打印出referenceTimeStamp + ((i + 1) * 1000) - beforeTimeStamp以瞭解我的意思

+0

+1,因爲我認爲這是解決代碼中直接錯誤的唯一答案。 – 2009-09-07 10:40:42

+0

Mhhh,我不確定1000-processingTime是否是我真正想要的,因爲在這種情況下,睡眠時間僅基於最後一步的信息。 使用我的解決方案,我將能夠避免一些漂移問題。但是因爲我對執行開銷沒有任何影響,所以我可能別無選擇,除非使用您的解決方案...或者? – Markus 2009-09-07 10:57:47

+0

唯一的解決方案實際上更接近你想要的是其他評論中的scheduleAtFixedRate - 其中的缺點,如果我正確理解你的問題,是你不能確定一個步驟完成之前,下一個開始(正在運行在不同的線程和所有) - 如果這不是一個問題,那麼一個ScheduledExecutorService將確保每個步驟開始1000毫秒後的前一個 – laura 2009-09-07 11:21:49

10

不能使用標準的Java時間確切量睡原因在於Java提供有關線程調度沒有絕對保障的事實。 Java受操作系統分配CPU時間的影響,並且程序將受到無法預測的垃圾收集暫停的影響。

如果您確實需要可預測的執行,那麼您需要查看realtime-specification for Java這在這裏是明顯的矯枉過正!

您可以在java.util.concurrent包中使用ScheduledExecutorService定期執行任務(通過休眠一段時間或以特定速率執行)。用法:

import static java.util.concurrent.* 

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

但這不準確(見的JavaDoc):但是

當心相對延遲的是過期不必與該任務已啓用當前日期一致由於網絡時間同步協議,時鐘漂移,或其它因素

(Emphasis mine)

+0

不管實時問題如何,他是不是應該睡覺(1000處理時間)的更簡單的問題? – 2009-09-07 10:15:54

+0

1000-處理時間問題是代碼中的一個錯誤。我的答案是解釋爲什麼整個方法有缺陷,是一個正確的答案,我不太明白它是如何值得downvote – 2009-09-07 10:19:15

+0

嗯,我認爲直接問題*是*代碼中的錯誤在哪裏。然而,跟上這個問題,你不可能做到這一點是值得的。也許downvote太苛刻了。刪除。 – 2009-09-07 10:39:48

2

正如others所示,您應該睡眠1000-處理時間。

忽略Java SE不提供實時平臺的事實(因此您不會獲得精確性),我可能會看看Timer類,特別是Timer.scheduleAtFixedRate(),它會照顧定期安排任務。

3

有一個在Java開始使用Java 5

看看ScheduledExecutorService一個簡單的標準解決方案。

它會是這個樣子:

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

凡mycode的類實現Runnable接口,將執行一次第二。

這不是一個實時保證,但應該足夠您的情況。

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)是第二個循環的正確睡眠時間。

Java的睡眠不準確,但它不可能如此遙遠。我認爲你要麼在調試器中中斷程序,要麼代碼與輸出不匹配。

+0

哦,對不起。我忘了提,我現在不睡覺。因此,這些值可能與您的預期不同。 – Markus 2009-09-07 11:14:58