2014-11-15 73 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添加到調度庫中,可以解決這個臭名昭着的問題,在未來的事件已經到達隊列的前端之後,不再服務新事件。)