2017-05-03 210 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