2017-05-03 107 views
0

我有一段時間True循環向外部函數發送變量,然後使用返回的值。此發送/接收過程具有用戶可配置的頻率,可從外部.ini配置文件保存和讀取。Python中的準確睡眠/延遲while循環

我試過time.sleep(1 /頻率),但由於其他地方使用的線程數量不夠準確。例如。 60Hz的頻率(週期爲0.0166667)給出了一個'實際'的時間。休眠()週期爲〜0.0311。

我更傾向於將使用附加while循環,它比較當前時間的開始時間加上期間,如下:

EndTime = time.time() + (1/Frequency) 
while time.time() - EndTime < 0: 
    sleep(0) 

這適合我的,而真正的函數的結尾爲如下:

while True: 
    A = random.randint(0, 5) 
    B = random.randint(0, 10) 
    C = random.randint(0, 20) 

    Values = ExternalFunction.main(Variable_A = A, Variable_B = B, Variable_C = C) 

    Return_A = Values['A_Out'] 
    Return_B = Values['B_Out'] 
    Return_C = Values['C_Out'] 

    #Updated other functions with Return_A, Return_B and Return_C 

    EndTime = time.time() + (1/Frequency) 
    while time.time() - EndTime < 0: 
     time.sleep(0) 

我錯過了一些東西,因爲while循環的添加導致函數只執行一次。我怎樣才能讓上述功能正常工作?這是在非實時操作系統上「準確」控制頻率的最佳方法嗎?我應該使用線程來處理這個特定的組件嗎?我正在Windows 7(64位)和Ubuntu(64位)上測試此功能。

+0

你想在給定的頻率下執行'ExternalFunction.main'嗎? –

+0

是的,這是正確的。我過去使用過threading.timer()和apscheduler;也許這些選擇會更好?編輯:apscheduler只接受第二個整數,所以不適合毫秒精度。 – jars121

+0

我認爲你在正確的軌道上,我的答案基本上是建議存儲循環前的時間,並在最後「填充」剩餘時間。非常類似於你在做什麼。 –

回答

1

如果我正確理解您的問題,您希望以給定的頻率執行ExternalFunction.main。問題是執行ExternalFunction.main本身需要一些時間。如果你不需要非常好的精度 - 看起來你沒有 - 我的建議是做這樣的事情。

import time 

frequency = 1 # Hz 
period = 1.0/frequency 

while True: 
    time_before = time.time() 
    [...] 
    ExternalFunction.main([...]) 
    [...] 
    while (time.time() - time_before) < period: 
     time.sleep(0.001) # precision here 

您可以調整精度以滿足您的需求。更高的精度(更小的數量)將使內部while循環更頻繁地執行。

這可以在不使用線程時獲得體面的結果。但是,當使用Python線程時,GIL(全局解釋器鎖)確保一次只運行一個線程。如果你有大量的線程,它可能會花費太多時間讓程序返回到主線程。增加頻率之間的Python變化可能會給您更準確的延遲。

將此添加到代碼的開頭以增加線程切換頻率。

import sys 
sys.setcheckinterval(1) 

1是(默認爲100)的切換之前在每個線程上執行的指令數,較大的數量,從而提高性能,但會增加線程切換時間。

+0

感謝雨果。我剛剛實施了您的方法,並遇到同樣的問題。 1/60秒的週期(即60Hz頻率)導致0.0311秒的實際延遲,這大約是0.016667的預期延遲的兩倍。 – jars121

+0

呃,有沒有機會使用'ExternalFunction.main'多於期望的時間? –

+0

一旦ExternalFunction.main函數返回,僅在while(time.time() - time_before) jars121

0

你可能想嘗試python-pause

暫停,直到UNIX時間,精確到毫秒:

import pause 
pause.until(1370640569.7747359) 

暫停使用日期時間:

import pause, datetime 
dt = datetime.datetime(2013, 6, 2, 14, 36, 34, 383752) 
pause.until(dt) 

您可以使用它如:

freqHz=60.0 
td=datetime.timedelta(seconds=1/freqHz) 
dt=datetime.now() 

while true: 
    #Your code here 
    dt+=td 
    pause.until(dt) 
+0

謝謝xvan。我剛剛嘗試了暫停模塊,包括pause.until,pause.seconds和pause.milliseconds,但根據所有其他建議和嘗試的方法,發現「實際」延遲始終爲0.0311。 – jars121