2014-11-15 72 views
2

我对python开发很陌生,我需要每x秒调用一次函数。
所以我试图用一个计时器的,是这样的:python,从主线程调用定时器回调方法

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()方法需要在主线程中调用,我想使用定时器导致它在不同的执行线。

所以我的问题是,我怎么能在主线程上调用这个方法?

+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(里面的时间),所以它会调用它自己在10秒后等,但我删除了第二个计时器。

+0

亚,但我如何确保do_some_work将在主线程上调用? – Mario

+0

@Mario - 在这个例子中,它不会。您必须启发我们,了解您的主线所做的事情,以便我们能够帮助您。它也可能有助于你解释为什么它需要在主线程上运行。 –

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属性,根据它的值,它只能在主线程上运行,在主线程或共享/组线程上运行,或者独立运行在它自己的线程上。这种方式可以运行更多或更多时间敏感的任务,而不会导致其他线程的速度变慢或接近预定的时间。 我不知道是否取决于线程的实现细节:是我的'如果不是主线程:time.sleep(秒);回报'有效地使它更有可能成为主线,我不应该担心差异。 (看起来像将我们的MAXBLOCKINGPERIOD作为第三个arg添加到调度库中,可以解决这个臭名昭着的问题,在未来的事件已经到达队列的前端之后,不再服务新事件。)