python 2.7中的可线程延迟

时间:2013-03-20 19:29:42

标签: python multithreading timer delay flags

我目前正在使用python(2.7)编写一个有一些线程的GUI。我遇到了一个问题,我需要在获取一条信息之前做大约大约一秒钟的延迟,但我不能让这个函数花费超过几毫秒来运行。考虑到这一点,我正在尝试创建一个Threaded计时器,它将设置一个标志timer.doneFlag并具有主要功能,以便继续查看它是否已完成。

它正在发挥作用。但不是所有的时间。我遇到的问题是,有时我感觉像time.sleep中的run函数,不会等待一秒钟(有时甚至可能不等待)。我需要的是我可以有一个标志,允许我控制开始时间并在达到1秒时抬起标志。

我可能做的太多只是为了得到一个可线程的延迟,如果你可以提出建议,或者帮助我在下面的代码中找到一个bug,我将非常感激!

我附上了我使用的部分代码:

来自主程序:

class dataCollection:
    def __init__(self):
        self.timer=Timer(5)
        self.isTimerStarted=0  
        return

    def StateFunction(self): #Try to finish the function within a few milliseconds

        if self.isTimerStarted==0:
           self.timer=Timer(1.0)
           self.timer.start()
           self.isTimerStarted=1

        if self.timer.doneFlag:
           self.timer.doneFlag=0
           self.isTimerStarted=0
           #and all the other code



import time
import threading
class Timer(threading.Thread):          
    def __init__(self, seconds):            
        self.runTime = seconds          
        self.doneFlag=0
        threading.Thread.__init__(self)
    def run(self):      
        time.sleep(self.runTime)    
        self.doneFlag=1
        print "Buzzzz"

x=dataCollection()
while 1:
    x.StateFunction()
    time.sleep(0.1)

1 个答案:

答案 0 :(得分:0)

首先,您已经有效地重建了threading.Timer,但灵活性较低。所以我认为你最好使用现有的课程。 (为每个计时器实例创建一个线程有一些明显的缺点。但如果你只想要一个单次计时器,那很好。)

更重要的是,让主线程重复轮询doneFlag可能是一个坏主意。这意味着你必须尽可能多地调用你的状态函数,没有充分理由燃烧CPU。

大概你必须在几毫秒内返回的原因是你正在返回某种事件循环,大概是你的GUI(但是,例如,网络反应堆有相同的问题,使用相同的解决方案,所以我会保持一般性。)

如果是这样,几乎所有这样的事件循环都有办法在事件循环中安排定时回调 - Timer中的wxcallLater中的twisted等。所以,使用它。

如果您使用的框架没有类似的东西,那么希望至少有一些方法可以发送一个事件/触发信号/发布消息/从外部调用它。 (如果它是一个简单的基于文件描述符的反应堆,它可能没有那个,但你可以通过将一个管道扔进反应堆来自己添加它。)所以,改变你的Timer回调来指示事件循环,而不是编写轮询Timer的代码。

如果由于某种原因你真的需要轮询在线程之间共享的变量,那么你真的应该用ConditionRLock来保护它。在语言中无法保证,当线程0更新值时,线程1将立即看到新值,甚至永远。如果您了解CPython(特定版本)的内部结构,您通常可以证明GIL在特定情况下不需要锁定。但除此之外,这是一场比赛。

最后:

  

我遇到的问题是,有时我觉得运行中的time.sleep函数,不会等待一秒钟(有时甚至可能不等待)。

嗯,the documentation明确表示会发生这种情况:

  

实际暂停时间可能小于请求的时间,因为任何捕获的信号将在执行该信号的捕获程序后终止sleep()。

所以,如果你需要保证它实际上至少睡了1秒钟,那么这样做的唯一方法就是这样:

t0 = time.time()
dur = 1.0
while True:
    time.sleep(dur)
    t1 = time.time()
    dur = 1.0 - (t1 - t0)
    if dur <= 0:
        break