python,从定时器回调调用主线程上的方法

时间:2014-11-15 19:44:31

标签: python python-2.7 python-multithreading

我对python开发很新,我需要每隔x秒调用一次函数 所以我正在尝试使用计时器,例如:

def start_working_interval():
    def timer_tick():
        do_some_work() // need to be called on the main thread

        timer = threading.Timer(10.0, timer_tick)
        timer.start()

    timer = threading.Timer(10.0, timer_tick)
    timer.start()  

需要在主线程上调用do_some_work()方法,我认为使用定时器使其在不同的线程上执行。

所以我的问题是,如何在主线程上调用此方法?

2 个答案:

答案 0 :(得分:0)

我现在确定你想要实现的目标,但是我玩了你的代码并做了这个:

import threading
import datetime


def do_some_work():
    print datetime.datetime.now()

def start_working_interval():
    def timer_tick():
        do_some_work()  

        timer = threading.Timer(10.0, timer_tick)
        timer.start()
    timer_tick()

start_working_interval()

所以基本上我所做的就是在timer_tick()中设置Time,这样它会在10秒后调用它自己,依此类推,但我删除了第二个计时器。

答案 1 :(得分:0)

我也需要这样做,这就是我所做的:

import time

MAXBLOCKINGSECONDS=5 #maximum time that a new task will have to wait before it's presence in the queue gets noticed.
class repeater:
    repeatergroup=[]                        #our only static data member it holds the current list of the repeaters that need to be serviced
    def __init__(self,callback,interval):
        self.callback=callback              
        self.interval=abs(interval)         #because negative makes no sense, probably assert would be better.
        self.reset()
        self.processing=False
    def reset(self):
        self.nextevent=time.time()+self.interval
    def whennext(self):
        return self.nextevent-time.time()   #time until next event
    def service(self):
        if time.time()>=self.nextevent:
            if self.processing=True:        #or however you want to be re-entrant safe or thread safe
                return 0
            self.processing==True
            self.callback(self)             #just stuff all your args into the class and pull them back out?

            #use this calculation if you don't want slew
            self.nextevent+=self.interval
            #reuse this calculation if you do want slew/don't want backlog
            #self.reset()
            #or put it just before the callback
            self.processing=False
            return 1
        return 0

    #this the transition code between class and classgroup
    #I had these three as a property getter and setter but it was behaving badly/oddly
    def isenabled(self):
        return (self in self.repeatergroup)
    def start(self):
        if not (self in self.repeatergroup):
            self.repeatergroup.append(self)
            #another logical place to call reset if you don't want backlog:
            #self.reset()
    def stop(self):
        if (self in self.repeatergroup):
            self.repeatergroup.remove(self)

    #group calls in c++ I'd make these static
    def serviceall(self):                   #the VB hacker in me wants to name this doevents(), the c hacker in me wants to name this probe
        ret=0
        for r in self.repeatergroup:
            ret+=r.service()
        return ret
    def minwhennext(self,max):              #this should probably be hidden
        ret=max
        for r in self.repeatergroup:
            ret=min(ret,r.whennext())
        return ret
    def sleep(self,seconds):
        if not isinstance(threading.current_thread(), threading._MainThread): #if we're not on the main thread, don't process handlers, just sleep.
            time.sleep(seconds)
            return
        endtime=time.time()+seconds         #record when caller wants control back
        while time.time()<=endtime:         #spin until then
            while self.serviceall()>0:      #service each member of the group until none need service
                if (time.time()>=endtime):
                    return                  #break out of service loop if caller needs control back already
            #done with servicing for a while, yield control to os until we have
            #another repeater to service or it's time to return control to the caller
            minsleeptime=min(endtime-time.time(),MAXBLOCKINGPERIOD) #smaller of caller's requested blocking time, and our sanity number (1 min might be find for some systems, 5 seconds is good for some systems, 0.25 to 0.03 might be better if there could be video refresh code waiting, 0.15-0.3 seems a common range for software denouncing of hardware buttons.
            minsleeptime=self.minwhennext(minsleeptime)
            time.sleep(max(0,minsleeptime))
###################################################################
#  and now some demo code:

def handler1(repeater):
    print("latency is currently {0:0.7}".format(time.time()-repeater.nextevent))
    repeater.count+=repeater.interval
    print("Seconds: {0}".format(repeater.count))

def handler2(repeater):                     #or self if you prefer
    print("Timed message is: {0}".format(repeater.message))
    if repeater.other.isenabled():
        repeater.other.stop()
    else:
        repeater.other.start()
    repeater.interval+=1

def demo_main():
    counter=repeater(handler1,1)
    counter.count=0                         #I'm still new enough to python
    counter.start()
    greeter=repeater(handler2,2)
    greeter.message="Hello world."          #that this feels like cheating
    greeter.other=counter                   #but it simplifies everything.
    greeter.start()
    print ("Currently {0} repeaters in service group.".format(len(repeater.repeatergroup)))
    print("About to yield control for a while")
    greeter.sleep(10)

    print("Got control back, going to do some processing")
    time.sleep(5)

    print("About to yield control for a while")      
    counter.sleep(20) #you can use any repeater to access sleep() but
    #it will only service those currently enabled.

    #notice how it gets behind but tries to catch up, we could add repeater.reset()
    #at the beginning of a handler to make it ignore missed events, or at the
    #end to let the timing slide, depending on what kind of processing we're doing
    #and what sort of sensitivity there is to time.

    #now just replace all your main thread's calls to time.sleep() with calls to mycounter.sleep()
    #now just add a repeater.sleep(.01) or a while repeater.serviceall(): pass to any loop that will take too long.
demo_main()

还有几件奇怪的事情需要考虑: 如果您更喜欢在处理程序中对您不关心的处理程序运行处理程序进行排序会更好吗?后来我继续添加一个threadingstyle属性,取决于它的值只能在主线程上运行,在主线程或共享/组线程上运行,或者独立于它自己的线程。这样,更长或更多时间敏感的任务可以在不导致其他线程减慢或接近其预定时间的情况下运行。 我想知道是否,取决于线程的实现细节:是否是我的&#39;如果不是主线程:time.sleep(seconds);返回&#39;有效地使它更有可能成为主线,我不应该担心这种差异。 (看起来像添加我们的MAXBLOCKINGPERIOD作为sched库的第3个arg可能会解决它在未来事件已经在队列前面的较长时间之后不再服务新事件的臭名昭着的问题。)