web-dev-qa-db-ja.com

Pythonのキャンセル可能なスレッド処理タイマー

特定の時間までカウントダウンするメソッドを作成しようとしていますが、再起動コマンドが指定されない限り、タスクを実行します。しかし、私はPython threading.Timerクラスを使用すると、タイマーをキャンセルできます。

import threading

def countdown(action):
    def printText():
        print 'hello!'

    t = threading.Timer(5.0, printText)
    if (action == 'reset'):
        t.cancel()

    t.start()

私は上記のコードが何らかの形で間違っていることを知っています。ここでいくつかの親切なガイダンスをいただければ幸いです。

33
Ted

タイマーを開始した後、キャンセルメソッドを呼び出します。

import time
import threading

def hello():
    print "hello, world"
    time.sleep(2)

t = threading.Timer(3.0, hello)
t.start()
var = 'something'
if var == 'something':
    t.cancel()

Timerを使用する代わりに、 Thread でwhileループを使用することを検討できます。
ニコラウス・グラドワールの answer から別の質問に割り当てられた例を次に示します。

import threading
import time

class TimerClass(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.event = threading.Event()
        self.count = 10

    def run(self):
        while self.count > 0 and not self.event.is_set():
            print self.count
            self.count -= 1
            self.event.wait(1)

    def stop(self):
        self.event.set()

tmr = TimerClass()
tmr.start()

time.sleep(3)

tmr.stop()
34
Honest Abe

正しく理解できるかどうかわかりません。この例のようなものを書きたいですか?

>>> import threading
>>> t = None
>>> 
>>> def sayHello():
...     global t
...     print "Hello!"
...     t = threading.Timer(0.5, sayHello)
...     t.start()
... 
>>> sayHello()
Hello!
Hello!
Hello!
Hello!
Hello!
>>> t.cancel()
>>>
13
Adam

threading.Timer class doesにはcancelメソッドがあり、threadをキャンセルしませんが、タイマーの実際の起動を停止します。実際に起こるのは、cancelメソッドがthreading.Event、およびスレッドが実際にthreading.Timerは、待機が完了した後、実際にコールバックを実行する前に、そのイベントをチェックします。

とは言っても、タイマーは通常実装されますwithoutそれぞれに個別のスレッドを使用します。それを行う最善の方法は、プログラムが実際に何を行っているか(このタイマーを待っている間)によって異なりますが、GUIやネットワークフレームワークなど、イベントループのあるものはすべて、イベントループにフックされるタイマーを要求する方法があります。

7
Thomas Wouters

上記の投稿に触発されました。 Pythonでのタイマーのキャンセルとリセット。スレッドを使用します。
機能:開始、停止、再起動、コールバック関数。
入力:タイムアウト、sleep_chunk値、およびcallback_function。
他のプログラムでこのクラスを使用または継承できます。コールバック関数に引数を渡すこともできます。
タイマーも途中で応答する必要があります。完全な睡眠時間の完了後だけではありません。したがって、1回の完全なスリープを使用する代わりに、小さなスリープチャンクを使用し、ループ内でイベントオブジェクトをチェックし続けました。

import threading
import time

class TimerThread(threading.Thread):
    def __init__(self, timeout=3, sleep_chunk=0.25, callback=None, *args):
        threading.Thread.__init__(self)

        self.timeout = timeout
        self.sleep_chunk = sleep_chunk
        if callback == None:
            self.callback = None
        else:
            self.callback = callback
        self.callback_args = args

        self.terminate_event = threading.Event()
        self.start_event = threading.Event()
        self.reset_event = threading.Event()
        self.count = self.timeout/self.sleep_chunk

    def run(self):
        while not self.terminate_event.is_set():
            while self.count > 0 and self.start_event.is_set():
                # print self.count
                # time.sleep(self.sleep_chunk)
                # if self.reset_event.is_set():
                if self.reset_event.wait(self.sleep_chunk):  # wait for a small chunk of timeout
                    self.reset_event.clear()
                    self.count = self.timeout/self.sleep_chunk  # reset
                self.count -= 1
            if self.count <= 0:
                self.start_event.clear()
                #print 'timeout. calling function...'
                self.callback(*self.callback_args)
                self.count = self.timeout/self.sleep_chunk  #reset

    def start_timer(self):
        self.start_event.set()

    def stop_timer(self):
        self.start_event.clear()
        self.count = self.timeout / self.sleep_chunk  # reset

    def restart_timer(self):
        # reset only if timer is running. otherwise start timer afresh
        if self.start_event.is_set():
            self.reset_event.set()
        else:
            self.start_event.set()

    def terminate(self):
        self.terminate_event.set()

#=================================================================
def my_callback_function():
    print 'timeout, do this...'

timeout = 6  # sec
sleep_chunk = .25  # sec

tmr = TimerThread(timeout, sleep_chunk, my_callback_function)
tmr.start()

quit = '0'
while True:
    quit = raw_input("Proceed or quit: ")
    if quit == 'q':
        tmr.terminate()
        tmr.join()
        break
    tmr.start_timer()
    if raw_input("Stop ? : ") == 's':
        tmr.stop_timer()
    if raw_input("Restart ? : ") == 'r':
        tmr.restart_timer()
0
manohar