web-dev-qa-db-ja.com

Python setInterval()と同等?

PythonはJavaScriptのsetInterval()に類似した関数を持っていますか?

ありがとう

43
zjm1126

これはあなたが探していた正しいスニペットかもしれません:

import threading

def set_interval(func, sec):
    def func_wrapper():
        set_interval(func, sec)
        func()
    t = threading.Timer(sec, func_wrapper)
    t.start()
    return t
30
stamat

これは、起動および停止できるバージョンです。ブロッキングではありません。実行時間エラーが追加されないため、グリッチもありません(たとえば、オーディオのように非常に短い間隔で長時間実行する場合に重要です)。

import time, threading

StartTime=time.time()

def action() :
    print('action ! -> time : {:.1f}s'.format(time.time()-StartTime))


class setInterval :
    def __init__(self,interval,action) :
        self.interval=interval
        self.action=action
        self.stopEvent=threading.Event()
        thread=threading.Thread(target=self.__setInterval)
        thread.start()

    def __setInterval(self) :
        nextTime=time.time()+self.interval
        while not self.stopEvent.wait(nextTime-time.time()) :
            nextTime+=self.interval
            self.action()

    def cancel(self) :
        self.stopEvent.set()

# start action every 0.6s
inter=setInterval(0.6,action)
print('just after setInterval -> time : {:.1f}s'.format(time.time()-StartTime))

# will stop interval in 5s
t=threading.Timer(5,inter.cancel)
t.start()

出力は:

just after setInterval -> time : 0.0s
action ! -> time : 0.6s
action ! -> time : 1.2s
action ! -> time : 1.8s
action ! -> time : 2.4s
action ! -> time : 3.0s
action ! -> time : 3.6s
action ! -> time : 4.2s
action ! -> time : 4.8s
10
doom

素敵でシンプルにしてください。

import threading

def setInterval(func,time):
    e = threading.Event()
    while not e.wait(time):
        func()

def foo():
    print "hello"

# using
setInterval(foo,5)

# output:
hello
hello
.
.
.

編集:このコードは非ブロッキングです

import threading

class ThreadJob(threading.Thread):
    def __init__(self,callback,event,interval):
        '''runs the callback function after interval seconds

        :param callback:  callback function to invoke
        :param event: external event for controlling the update operation
        :param interval: time in seconds after which are required to fire the callback
        :type callback: function
        :type interval: int
        '''
        self.callback = callback
        self.event = event
        self.interval = interval
        super(ThreadJob,self).__init__()

    def run(self):
        while not self.event.wait(self.interval):
            self.callback()



event = threading.Event()

def foo():
    print "hello"

k = ThreadJob(foo,event,2)
k.start()

print "It is non-blocking"
10
darxtrix

変更Nailxxの答えは少しで、あなたは答えを得ました!

from threading import Timer

def hello():
    print "hello, world"
    Timer(30.0, hello).start()

Timer(30.0, hello).start() # after 30 seconds, "hello, world" will be printed
7
Stephan Meijer

schedモジュールは、一般的なPythonコードにこれらの機能を提供します。ただし、そのドキュメントが示唆するように、コードがマルチスレッドである場合、threading.Timerクラスの代わりに。

6
Eli Bendersky

私はこれがあなたが望んでいることだと思います:

#timertest.py
import sched, time
def dostuff():
  print "stuff is being done!"
  s.enter(3, 1, dostuff, ())

s = sched.scheduler(time.time, time.sleep)
s.enter(3, 1, dostuff, ())
s.run()

繰り返しメソッドの最後に別のエントリをスケジューラに追加すると、そのまま続行されます。

3
visum

単純なsetInterval utils

from threading import Timer

def setInterval(timer, task):
    isStop = task()
    if not isStop:
        Timer(timer, setInterval, [timer, task]).start()

def hello():
    print "do something"
    return False # return True if you want to stop

if __name__ == "__main__":
    setInterval(2.0, hello) # every 2 seconds, "do something" will be printed
2
Tan Nguyen

上記の解決策では、プログラムがシャットダウンする状況が発生した場合、正常にシャットダウンする保証はありません。ソフトキルを介してプログラムをシャットダウンすることを常にお勧めします。ほとんどの場合、停止する機能もありませんでした。これらの問題の両方を解決するSankalpによって書かれた媒体( pythonで定期的なタスクを実行 )で、より深い洞察を得るために添付のリンクを参照してください。以下のサンプルでは、​​killという名前のライブラリを使用して、killがソフトkillまたはハードkillであるかどうかを追跡しています。

import threading, time, signal

from datetime import timedelta

WAIT_TIME_SECONDS = 1

class ProgramKilled(Exception):
    pass

def foo():
    print time.ctime()

def signal_handler(signum, frame):
    raise ProgramKilled

class Job(threading.Thread):
    def __init__(self, interval, execute, *args, **kwargs):
        threading.Thread.__init__(self)
        self.daemon = False
        self.stopped = threading.Event()
        self.interval = interval
        self.execute = execute
        self.args = args
        self.kwargs = kwargs

    def stop(self):
                self.stopped.set()
                self.join()
    def run(self):
            while not self.stopped.wait(self.interval.total_seconds()):
                self.execute(*self.args, **self.kwargs)

if __name__ == "__main__":
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)
    job = Job(interval=timedelta(seconds=WAIT_TIME_SECONDS), execute=foo)
    job.start()

    while True:
          try:
              time.sleep(1)
          except ProgramKilled:
              print "Program killed: running cleanup code"
              job.stop()
              break
#output
#Tue Oct 16 17:47:51 2018
#Tue Oct 16 17:47:52 2018
#Tue Oct 16 17:47:53 2018
#^CProgram killed: running cleanup code
1
Pavan Varyani

上記の答えのほとんどは、スレッドを適切にシャットダウンしません。 Jupyterノートブックを使用しているときに、明示的な割り込みが送信されたときにスレッドがまだ実行中であり、さらに悪いことに、スレッドが1、2、4などで増加し続けることに気付きました。以下の私の方法は、@ Doomによる回答に基づいていますが、きれいメインスレッドで無限ループを実行してSIGINTおよびSIGTERMイベントをリッスンすることにより、割り込みを処理します

  • ドリフトなし
  • キャンセル可能
  • SIGINTとSIGTERMを非常にうまく処理します
  • 実行ごとに新しいスレッドを作成しない

改善を提案すること自由に感じなさい

import time
import threading
import signal

# Record the time for the purposes of demonstration 
start_time=time.time()

class ProgramKilled(Exception):
    """
    An instance of this custom exception class will be thrown everytime we get an SIGTERM or SIGINT
    """
    pass

# Raise the custom exception whenever SIGINT or SIGTERM is triggered
def signal_handler(signum, frame):
    raise ProgramKilled

# This function serves as the callback triggered on every run of our IntervalThread
def action() :
    print('action ! -> time : {:.1f}s'.format(time.time()-start_time))

# https://stackoverflow.com/questions/2697039/python-equivalent-of-setinterval
class IntervalThread(threading.Thread) :
    def __init__(self,interval,action, *args, **kwargs) :
        super(IntervalThread, self).__init__()
        self.interval=interval
        self.action=action
        self.stopEvent=threading.Event()
        self.start()

    def run(self) :
        nextTime=time.time()+self.interval
        while not self.stopEvent.wait(nextTime-time.time()) :
            nextTime+=self.interval
            self.action()

    def cancel(self) :
        self.stopEvent.set()

def main():

    # Handle SIGINT and SIFTERM with the help of the callback function
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)
    # start action every 1s
    inter=IntervalThread(1,action)
    print('just after setInterval -> time : {:.1f}s'.format(time.time()-start_time))

    # will stop interval in 500s
    t=threading.Timer(500,inter.cancel)
    t.start()

    # https://www.g-loaded.eu/2016/11/24/how-to-terminate-running-python-threads-using-signals/
    while True:
        try:
            time.sleep(1)
        except ProgramKilled:
            print("Program killed: running cleanup code")
            inter.cancel()
            break

if __name__ == "__main__":
    main()
0
PirateApp

最近、あなたと同じ問題があります。そして私はこれらの解決策を見つけます:

1。ライブラリを使用できます: threading.Time (これには上記の導入があります)

2。ライブラリを使用できます: sched (これも上記の紹介があります)

3。ライブラリを使用できます: Advanced Python Scheduler(Recommend)

0
Ni Xiaoni

私のPython 3モジュールjsinterval.pyは役に立ちます!ここにあります:

"""
Threaded intervals and timeouts from JavaScript
"""

import threading, sys

__all__ =  ['TIMEOUTS', 'INTERVALS', 'setInterval', 'clearInterval', 'setTimeout', 'clearTimeout']

TIMEOUTS  = {}
INTERVALS = {}

last_timeout_id  = 0
last_interval_id = 0

class Timeout:
    """Class for all timeouts."""
    def __init__(self, func, timeout):
        global last_timeout_id
        last_timeout_id += 1
        self.timeout_id = last_timeout_id
        TIMEOUTS[str(self.timeout_id)] = self
        self.func = func
        self.timeout = timeout
        self.threadname = 'Timeout #%s' %self.timeout_id

    def run(self):
        func = self.func
        delx = self.__del__
        def func_wrapper():
            func()
            delx()
        self.t = threading.Timer(self.timeout/1000, func_wrapper)
        self.t.name = self.threadname
        self.t.start()

    def __repr__(self):
        return '<JS Timeout set for %s seconds, launching function %s on timeout reached>' %(self.timeout, repr(self.func))

    def __del__(self):
        self.t.cancel()

class Interval:
    """Class for all intervals."""
    def __init__(self, func, interval):
        global last_interval_id
        self.interval_id = last_interval_id
        INTERVALS[str(self.interval_id)] = self
        last_interval_id += 1
        self.func = func
        self.interval = interval
        self.threadname = 'Interval #%s' %self.interval_id

    def run(self):
        func = self.func
        interval = self.interval
        def func_wrapper():
            timeout = Timeout(func_wrapper, interval)
            self.timeout = timeout
            timeout.run()
            func()
        self.t = threading.Timer(self.interval/1000, func_wrapper)
        self.t.name = self.threadname
        self.t.run()

    def __repr__(self):
        return '<JS Interval, repeating function %s with interval %s>' %(repr(self.func), self.interval)

    def __del__(self):
        self.timeout.__del__()

def setInterval(func, interval):
    """
    Create a JS Interval: func is the function to repeat, interval is the interval (in ms)
    of executing the function.
    """
    temp = Interval(func, interval)
    temp.run()
    idx = int(temp.interval_id)
    del temp
    return idx


def clearInterval(interval_id):
    try:
        INTERVALS[str(interval_id)].__del__()
        del INTERVALS[str(interval_id)]
    except KeyError:
        sys.stderr.write('No such interval "Interval #%s"\n' %interval_id)

def setTimeout(func, timeout):
    """
    Create a JS Timeout: func is the function to timeout, timeout is the timeout (in ms)
    of executing the function.
    """
    temp = Timeout(func, timeout)
    temp.run()
    idx = int(temp.timeout_id)
    del temp
    return idx


def clearTimeout(timeout_id):
    try:
        TIMEOUTS[str(timeout_id)].__del__()
        del TIMEOUTS[str(timeout_id)]
    except KeyError:
        sys.stderr.write('No such timeout "Timeout #%s"\n' %timeout_id)

コード編集:メモリリークが修正されました(@benjaminzによって発見)。これで、すべてのスレッドが終了時にクリーンアップされます。なぜこのリークが発生するのですか?暗黙的な(または明示的な)参照のために発生します。私の場合、TIMEOUTSINTERVALSです。タイムアウトは、関数を呼び出してからセルフキルする関数ラッパーを使用するため、(このパッチの後)自動的に自動クリーンアップします。しかし、これはどうやって起こるのでしょうか?すべての参照も削除されるか、gcモジュールが使用されない限り、オブジェクトはメモリから削除できません。説明:(私のコードでは)タイムアウト/間隔への不要な参照を作成する方法はありません。参照元は1つだけです:TIMEOUTS/INTERVALS辞書。そして、中断または終了すると(タイムアウトのみが中断なしに終了できる)、自分自身への既存の参照、つまり対応するdict要素のみが削除されます。クラスは__all__を使用して完全にカプセル化されるため、メモリリークのためのスペースはありません。

0

私は非常に柔軟なsetIntervalをpythonで作成するコードを記述しました。はい、どうぞ:

import threading

class AlreadyRunning(Exception):
    pass
class IntervalNotValid(Exception):
    pass
class setInterval():
    def __init__(this,func=None, sec=None,args=[]):
        this.running=False       
        this.func=func          #the function to be run
        this.sec=sec            #interval in second
        this.Return=None        #The returned data
        this.args=args
        this.runOnce=None       #asociated with run_once() method
        this.runOnceArgs=None   #asociated with run_once() method
        if (func!=None and sec!=None):
            this.running=True
            if (not callable(func)):
                raise TypeError("non-callable object is given")
            if (type(sec)!=type(1) and type(sec)!=type(0.1)):
                raise TypeError("A non-numeric object is given")
            this.TIMER=threading.Timer(this.sec, this.loop)
            this.TIMER.start()

    def start(this):
        if (not this.running):
            if (not this.isValid()):
                raise IntervalNotValid("The function and/or the interval hasn't provided or invalid.")
            this.running=True
            this.TIMER=threading.Timer(this.sec, this.loop)
            this.TIMER.start()
        else:
            raise AlreadyRunning("Tried to run an already run interval")

    def stop(this):
        this.running=False

    def isValid(this):
        if (not callable(this.func)):
            return False
        if (type(this.sec)!=type(1) and type(this.sec)!=type(0.1)):
            return False
        return True

    def loop(this):
        if (this.running):
            this.TIMER=threading.Timer(this.sec, this.loop)
            this.TIMER.start()
            function_,Args_=this.func,this.args
            if (this.runOnce!=None): #someone has provide the run_once
                runOnce,this.runOnce=this.runOnce,None
                result=runOnce( *(this.runOnceArgs)  )
                this.runOnceArgs=None
                if ( result == False ): #if and only if the result is False. not accept "None" nor zero.
                    return ; #cancel the interval right now
            this.Return=function_(*Args_)

    def change_interval(this,sec):
        if (type(sec)!=type(1) and type(sec)!=type(0.1)):
            raise TypeError("A non-numeric object is given")
        if (this.running): #prevent error when providing interval to a blueprint
            this.TIMER.cancel()
        this.sec=sec
        if (this.running): #prevent error when providing interval to a blueprint if the function hasn't provided yet
            this.TIMER=threading.Timer(this.sec, this.loop); this.TIMER.start()

    def change_next_interval(this,sec):
        if (type(sec)!=type(1) and type(sec)!=type(0.1)):
            raise TypeError("A non-numeric object is given")
        this.sec=sec

    def change_func(this,func,args=[]):
        if (not callable(func)):
            raise TypeError("non-callable object is given")
        this.func=func
        this.args=args

    def run_once(this,func,args=[]):
        this.runOnce=func
        this.runOnceArgs=args
    def get_return(this):
        return this.Return

多くの機能と柔軟性を得ることができます。このコードを実行してもコードはフリーズしません。実行時に間隔を変更したり、実行時に関数を変更したり、引数を渡したり、関数から返されたオブジェクトを取得したりできます。あなたもあなたのトリックを作ることができます!

使用するための非常にシンプルで基本的な例を次に示します。

import time

def interval(name="world"):
  print(f"Hello {name}!")

# function named interval will be called every two seconds
#output: "Hello world!"
interval1 = setInterval(interval, 2) 

# function named interval will be called every 1.5 seconds
#output: "Hello Jane!"
interval2 = setInterval(interval, 1.5, ["Jane"]) 

time.sleep(5) #stop all intervals after 5 seconds
interval1.stop()
interval2.stop()

私のGithubプロジェクトをチェックして、他の例を確認し、次の更新に従ってください:D https://github.com/Hzzkygcs/setInterval-python

0
KhunRan

間隔をキャンセルできるようにする必要があったため、上記の方法ではうまくいきませんでした。私は関数をクラスに変えて、次のことを思いつきました:

class setInterval():
    def __init__(self, func, sec):
        def func_wrapper():
            self.t = threading.Timer(sec, func_wrapper)
            self.t.start()
            func()
        self.t = threading.Timer(sec, func_wrapper)
        self.t.start()

    def cancel(self):
        self.t.cancel()
0
Wesley

func_wrapperthreading.Timerを使用する上記のいくつかの回答は実際に機能しますが、間隔が呼び出されるたびに新しいスレッドを生成するため、メモリの問題が発生します。

以下の基本的な例おおまかには、別のスレッドに間隔を置くことにより、同様のメカニズムを実装しました。指定された間隔でスリープします。コードにジャンプする前に、注意する必要があるいくつかの制限を次に示します。

  1. JavaScriptはシングルスレッドであるため、setInterval内の関数が呼び出されると、他に何も動作しません(ワーカースレッドを除きますが、setIntervalの一般的な使用例について説明します。したがって、スレッド化安全ですが、この実装では、threading.rLockを使用しないと競合状態が発生する可能性があります。

  2. 以下の実装はtime.sleepを使用して間隔をシミュレートしますが、funcの実行時間を追加すると、これの合計時間intervalは予想よりも長くなる可能性があります。したがって、ユースケースによっては、「スリープレス」(funcの呼び出しにかかる時間のマイナス)が必要になる場合があります。

  3. 私はおおまかにのみをテストしました。私が行った方法のようにグローバル変数を使用することは絶対に避けてください。システムに合うように自由に調整してください。


十分に話して、ここにコードがあります:

# Python 2.7
import threading
import time


class Interval(object):
    def __init__(self):
        self.daemon_alive = True
        self.thread = None # keep a reference to the thread so that we can "join"

    def ticktock(self, interval, func):
        while self.daemon_alive:
            time.sleep(interval)
            func()

num = 0
def print_num():
    global num
    num += 1
    print 'num + 1 = ', num

def print_negative_num():
    global num
    print '-num = ', num * -1

intervals = {} # keep track of intervals
g_id_counter = 0 # roughly generate ids for intervals

def set_interval(interval, func):
    global g_id_counter

    interval_obj = Interval()
    # Put this interval on a new thread
    t = threading.Thread(target=interval_obj.ticktock, args=(interval, func))
    t.setDaemon(True)
    interval_obj.thread = t
    t.start()

    # Register this interval so that we can clear it later
    # using roughly generated id
    interval_id = g_id_counter
    g_id_counter += 1
    intervals[interval_id] = interval_obj

    # return interval id like it does in JavaScript
    return interval_id

def clear_interval(interval_id):
    # terminate this interval's while loop
    intervals[interval_id].daemon_alive = False
    # kill the thread
    intervals[interval_id].thread.join()
    # pop out the interval from registry for reusing
    intervals.pop(interval_id)

if __name__ == '__main__':
    num_interval = set_interval(1, print_num)
    neg_interval = set_interval(3, print_negative_num)

    time.sleep(10) # Sleep 10 seconds on main thread to let interval run
    clear_interval(num_interval)
    clear_interval(neg_interval)
    print "- Are intervals all cleared?"
    time.sleep(3) # check if both intervals are stopped (not printing)
    print "- Yup, time to get beers"

期待される出力:

num + 1 =  1
num + 1 =  2
-num =  -2
 num + 1 =  3
num + 1 =  4
num + 1 =  5
-num =  -5
num + 1 =  6
num + 1 =  7
num + 1 =  8
-num =  -8
num + 1 =  9
num + 1 =  10
-num =  -10
Are intervals all cleared?
Yup, time to get beers
0
benjaminz

以下は、スレッドを使用して定期的にイベントオブジェクトにシグナルを送信する、低ドリフトのソリューションです。タイムアウトを待つ間、スレッドのrun()はほとんど何もしません。したがって、時間ドリフトが低くなります。

# Example of low drift (time) periodic execution of a function.
import threading
import time

# Thread that sets 'flag' after 'timeout'
class timerThread (threading.Thread):

    def __init__(self , timeout , flag):
        threading.Thread.__init__(self)
        self.timeout = timeout
        self.stopFlag = False
        self.event = threading.Event()
        self.flag = flag

    # Low drift run(); there is only the 'if'
    # and 'set' methods between waits.
    def run(self):
        while not self.event.wait(self.timeout):
            if self.stopFlag:
                break
            self.flag.set()

    def stop(self):
        stopFlag = True
        self.event.set()

# Data.
printCnt = 0

# Flag to print.
printFlag = threading.Event()

# Create and start the timer thread.
printThread = timerThread(3 , printFlag)
printThread.start()

# Loop to wait for flag and print time.
while True:

    global printCnt

    # Wait for flag.
    printFlag.wait()
    # Flag must be manually cleared.
    printFlag.clear()
    print(time.time())
    printCnt += 1
    if printCnt == 3:
        break;

# Stop the thread and exit.
printThread.stop()
printThread.join()
print('Done')
0
bobwirka