x秒ごとに関数を繰り返し実行する最良の方法は何ですか?


281

(Objective CのNSTimerのように)60秒ごとにPythonで関数を繰り返し実行したいと思います。このコードはデーモンとして実行され、cronを使用して毎分Pythonスクリプトを呼び出すのとほぼ同じですが、ユーザーが設定する必要はありません。

ではPythonで実装するcronについて、この質問、ソリューションを効果的にだけに表示されます)(睡眠のx秒間。このような高度な機能は必要ないので、おそらくこのようなものが機能するでしょう

while True:
    # Code executed here
    time.sleep(60)

このコードに予見可能な問題はありますか?


83
重要なポイントですが、重要な場合があります。コードの上のコードは60秒ごとに実行されず、実行間に60秒のギャップが生じます。実行されたコードがまったく時間をかけない場合にのみ、60秒ごとに発生します。
Simon、

4
また、time.sleep(60)両方以前と後で返すことがあります。
JFS

5
私はまだ疑問に思っています:このコードに予測可能な問題はありますか?
バナナ

1
「予見可能な問題」は、time.sleep(60)を使用するだけでは1時間あたり60回の反復を期待できないことです。したがって、反復ごとに1つのアイテムを追加し、設定された長さのリストを保持している場合...そのリストの平均は、一貫した「期間」を表しません。そのため、「移動平均」などの関数は、古すぎるデータポイントを参照している可能性があり、指示を歪めます。
ライトプレゼンス2017

2
@バナナはい、スクリプトが60秒ごとに正確に実行されないため、問題が発生する可能性があります。例えば。ビデオストリームを分割してアップロードするために、このようなことを始めました。ループ内でデータを処理している間、メディアキューがバッファリングされているため、ストレムが5〜10秒長くなりました。それはあなたのデータに依存します。関数が、たとえばディスクがいっぱいになったときに警告する単純なウォッチドッグのようなものである場合、これで何の問題もないはずです。原子力発電所の警告アラートをチェックしている場合は、都市になる可能性がありますxを完全に爆破
DGoiko 2018年

回答:


227

プログラムにイベントループがまだない場合は、汎用イベントスケジューラを実装するschedモジュールを使用します。

import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc): 
    print("Doing stuff...")
    # do your stuff
    s.enter(60, 1, do_something, (sc,))

s.enter(60, 1, do_something, (s,))
s.run()

あなたは既にのようなイベントループライブラリを使用している場合はasynciotriotkinterPyQt5gobjectkivy、および他の多くの-ちょうどその代わりに、既存のイベントループライブラリのメソッドを使用してタスクをスケジュールします。


16
schedモジュールは、関数を一定時間後に実行するようにスケジュールするためのものです。これを使用して、time.sleep()を使用せずにx秒ごとに関数呼び出しを繰り返すにはどうすればよいですか?
Baishampayan Ghose

2
@Baishampayan:新しい実行をスケジュールしてください。
nosklo 2009年

3
次に、packages.python.org / APSchedulerのapscheduler もこの時点で言及されるはずです。
Daniel F

6
注:このバージョンはドリフトする可能性があります。あなたはenterabs()それを避けるために使うことができます。これは、比較のためのドリフトのないバージョンです
jfs 2014年

8
@JavaSa:「do your stuff」は瞬時ではなく、time.sleepここからエラーが蓄積される可能性があるためです。「X秒ごとに実行」と「〜X秒の遅延で繰り返し実行」は同じではありません。このコメント
jfs

180

時間ループをシステムクロックにロックするだけです。簡単です。

import time
starttime=time.time()
while True:
  print "tick"
  time.sleep(60.0 - ((time.time() - starttime) % 60.0))

22
+1。あなたとそのtwisted答えが、毎秒関数を実行する唯一の答えですx。残りは、x呼び出しごとに数秒の遅延で関数を実行します。
jfs 2014

13
これに1秒以上かかったコードを追加する場合...タイムアウトがスローされ、遅れが生じます。この場合、受け入れられる答えは正しいです...誰でも簡単な印刷コマンドをループできますそして、それを毎秒遅滞なく実行させる...
Angry 84

5
私が好むfrom time import time, sleep理由実存的な意味で。)
ウィル

14
素晴らしく機能します。starttimeあなたがそれを特定の時間に同期することから始めれば、あなたを差し引く必要はありません:time.sleep(60 - time.time() % 60)私にとってはうまくいきました。私はそれをそのまま使用し、希望どおりににtime.sleep(1200 - time.time() % 1200)ログを記録し:00 :20 :40ます。
TemporalWolf

2
@AntonSchigurは、複数回の反復後のドリフトを回避します。個々の反復はsleep()timer()精度、およびループ本体の実行にかかる時間に応じて、多少遅れて開始する場合がありますが、平均して、反復は間隔の境界で常に発生します(一部がスキップされた場合でも)while keep_doing_it(): sleep(interval - timer() % interval)while keep_doing_it(): sleep(interval)数回の反復後にエラーが蓄積する可能性のある場所と比較してください。
jfs

71

Reactorパターンを実装するPythonネットワークライブラリであるTwistedを検討することをお勧めします。

from twisted.internet import task, reactor

timeout = 60.0 # Sixty seconds

def doWork():
    #do work here
    pass

l = task.LoopingCall(doWork)
l.start(timeout) # call every sixty seconds

reactor.run()

「while True:sleep(60)」はおそらく動作しますが、Twistedはおそらく最終的に必要となる多くの機能(デーモン化、ロギング、またはbobinceによって指摘された例外処理)をすでに実装しており、おそらくより堅牢なソリューションになります。


素晴らしい答えも、ドリフトせずに非常に正確です。これにより、タスクの実行を待機している間もCPUがスリープ状態になるのでしょうか(ビジー待機ではありません)。
スムースウェア'16

1
ミリ秒レベルでこのドリフト
デレク・エデン

「ミリ秒レベルのドリフト」とはどういう意味ですか?
Jean-Paul Calderone

67

関数を定期的に実行する非ブロック方法が必要な場合は、ブロック無限ループの代わりに、スレッド化タイマーを使用します。このようにして、コードは実行を継続し、他のタスクを実行しながら、関数をn秒ごとに呼び出すことができます。CPU /ディスク/ネットワークを集中的に使用する長いタスクの進捗情報を印刷するために、この手法をよく使用しています。

start()およびstop()コントロールを使用して、同様の質問で私が投稿したコードは次のとおりです。

from threading import Timer

class RepeatedTimer(object):
    def __init__(self, interval, function, *args, **kwargs):
        self._timer     = None
        self.interval   = interval
        self.function   = function
        self.args       = args
        self.kwargs     = kwargs
        self.is_running = False
        self.start()

    def _run(self):
        self.is_running = False
        self.start()
        self.function(*self.args, **self.kwargs)

    def start(self):
        if not self.is_running:
            self._timer = Timer(self.interval, self._run)
            self._timer.start()
            self.is_running = True

    def stop(self):
        self._timer.cancel()
        self.is_running = False

使用法:

from time import sleep

def hello(name):
    print "Hello %s!" % name

print "starting..."
rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start()
try:
    sleep(5) # your long-running job goes here...
finally:
    rt.stop() # better in a try/finally block to make sure the program ends!

特徴:

  • 標準ライブラリのみ、外部依存関係なし
  • start()そしてstop()、タイマーが既に開始されている場合でも、複数回呼び出すことが安全である/停止
  • 呼び出される関数は、位置引数と名前付き引数を持つことができます
  • intervalいつでも変更でき、次回の実行後に有効になります。同じのためargskwargsとさえfunction

このソリューションは、時間の経過とともにドリフトするようです。ドリフトなしでn秒ごとに関数を呼び出すことを目的としたバージョンが必要でした。別の質問で更新を投稿します。
eraoul 2016

ではdef _run(self)、なぜあなたがself.start()前に電話をするのかについて頭を抱えようとしていますself.function()。詳しく説明できますか?start()最初に呼び出すself.is_runningと常にそうなるFalseので、常に新しいスレッドを起動します。
リッチエピスコポ2016

1
私はそれの底に達したと思います。@MestreLionのソリューションは1 x秒ごとに関数を実行します(つまり、t = 0、t = 1x、t = 2x、t = 3x、...)。元のポスターでは、サンプルコードはx秒間隔で関数を実行します。また、このソリューションには、実行intervalにかかる時間よりも短い場合にバグがあると思いますfunction。その場合、関数でself._timer上書きされstartます。
リッチエピスコポ2016

はい、@RichieEpiscopo、への呼び出し.function()の後には、.start()t = 0で機能を実行することです。そして、functionそれより長くかかっても問題にならないと思いますintervalが、はい、コードにいくつかの競合状態があるかもしれません。
MestreLion 2017

これは私が得ることができる唯一の非ブロッキング方法です。ありがとう。
backslashN

35

私が信じるより簡単な方法:

import time

def executeSomething():
    #code here
    time.sleep(60)

while True:
    executeSomething()

このようにしてコードが実行されると、60秒待機してから再度実行され、待機、実行などが行われます。物事を複雑にする必要はありません。D


キーワードTrueは大文字にする必要があります
Sean Cain

38
実際、これは答えではありません。timesleep()は、すべての実行後にX秒待機するためにのみ使用できます。たとえば、関数の実行に0.5秒かかり、time.sleep(1)を使用する場合、関数は1ではなく1.5秒ごとに実行されることを意味します。他のモジュールまたはスレッド、あるいはその両方を使用して、何かがY回動作することを確認する必要がありますX秒ごと。
kommradHomer 2013

1
@kommradHomer:デイブ・ローブの答えはあなたがいることを証明することができます使用してtime.sleep()X秒ごとに実行何かを
JFS

2
私の意見でコードが呼び出す必要がありますtime.sleep()while Trueのようなループ:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
レナードLepadatu

22
import time, traceback

def every(delay, task):
  next_time = time.time() + delay
  while True:
    time.sleep(max(0, next_time - time.time()))
    try:
      task()
    except Exception:
      traceback.print_exc()
      # in production code you might want to have this instead of course:
      # logger.exception("Problem while executing repetitive task.")
    # skip tasks if we are behind schedule:
    next_time += (time.time() - next_time) // delay * delay + delay

def foo():
  print("foo", time.time())

every(5, foo)

残りのコードをブロックせずにこれを実行したい場合は、これを使用して独自のスレッドで実行することができます。

import threading
threading.Thread(target=lambda: every(5, foo)).start()

このソリューションは、他のソリューションではほとんど見られない機能をいくつか組み合わせています。

  • 例外処理:このレベルで可能な限り、例外は適切に処理されます。つまり、プログラムを中止せずにデバッグ目的でログに記録されます。
  • チェーニングなし:多くの回答で見つけられる一般的なチェインのような実装(次のイベントをスケジュールするため)は、スケジューリングメカニズム(threading.Timerまたはその他)内で何か問題が発生すると、チェインが終了するという点で脆弱です。問題の理由がすでに修正されていても、それ以上の実行は行われません。単純なループと単純なループの待機は、sleep()比較するとはるかに堅牢です。
  • ドリフトなし:私のソリューションは、実行する予定の時間を正確に追跡します。他の多くのソリューションのように、実行時間に依存するドリフトはありません。
  • スキップ: 1つの実行に時間がかかりすぎた場合、私のソリューションではタスクをスキップします(たとえば、5秒ごとにXを実行しますが、Xは6秒かかりました)。これは標準のcronの動作です(そして、それには十分な理由があります)。他の多くのソリューションでは、遅延なしに、タスクを数回続けて実行します。ほとんどの場合(たとえば、クリーンアップタスク)、これは望ましくありません。必要応じて、next_time += delay代わりに使用してください。

2
ドリフトしないための最良の答え。
セバスチャンスターク

1
@PirateApp別のスレッドでこれを行います。あなた同じスレッドでそれを行うことができますが、それではコメントのためにはあまりにも複雑な独自のスケジューリングシステムをプログラミングすることになります。
Alfe、

1
Pythonでは、GILのおかげで、2つのスレッドで変数にアクセスすることは完全に安全です。また、2つのスレッドでの単なる読み取りは問題にはなりません(他のスレッド環境でも同様)。GILのないシステム(Java、C ++など)で2つの異なるスレッドから書き込む場合のみ、明示的な同期が必要です。
Alfe

1
@ user50473これ以上の情報がなければ、まずスレッド側からタスクにアプローチします。1つのスレッドがデータを時々読み取り、再度実行するまでスリープ状態になります。上記のソリューションは、もちろんこれを行うために使用できます。しかし、私は別の方法をとる理由がたくさんあると想像できます。幸運を祈ります:)
Alfe

1
スリープは、threading.Event wait with timeoutで置き換えることができ、アプリケーションの終了時の応答性が向上します。stackoverflow.com/questions/29082268/...
themadmax

20

これは、時間の経過に伴う改造を回避するMestreLionからのコードの更新です。

ここでのRepeatedTimerクラスは、OPからの要求に応じて、指定された関数を「間隔」秒ごとに呼び出します。スケジュールは、関数の実行にかかる時間に依存しません。外部のライブラリに依存しないため、このソリューションが好きです。これは純粋なpythonです。

import threading 
import time

class RepeatedTimer(object):
  def __init__(self, interval, function, *args, **kwargs):
    self._timer = None
    self.interval = interval
    self.function = function
    self.args = args
    self.kwargs = kwargs
    self.is_running = False
    self.next_call = time.time()
    self.start()

  def _run(self):
    self.is_running = False
    self.start()
    self.function(*self.args, **self.kwargs)

  def start(self):
    if not self.is_running:
      self.next_call += self.interval
      self._timer = threading.Timer(self.next_call - time.time(), self._run)
      self._timer.start()
      self.is_running = True

  def stop(self):
    self._timer.cancel()
    self.is_running = False

使用例(MestreLionの回答からコピー):

from time import sleep

def hello(name):
    print "Hello %s!" % name

print "starting..."
rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start()
try:
    sleep(5) # your long-running job goes here...
finally:
    rt.stop() # better in a try/finally block to make sure the program ends!

5

しばらく前に同じような問題に直面しました。かもしれhttp://cronus.readthedocs.orgが役立つかもしれませんか?

v0.2の場合、次のスニペットが機能します

import cronus.beat as beat

beat.set_rate(2) # 2 Hz
while beat.true():
    # do some time consuming work here
    beat.sleep() # total loop duration would be 0.5 sec

4

それとcronの主な違いは、例外がデーモンを完全に強制終了することです。例外キャッチャーとロガーでラップしたいかもしれません。


4

考えられる答えの1つ:

import time
t=time.time()

while True:
    if time.time()-t>10:
        #run your task here
        t=time.time()

1
これは待機中のため、非常に悪い状態です。
Alfe、2018

非ブロッキングタイマーを探している人に適したソリューションです。
ノエル

3

結局、スケジュールモジュールを使ってしまいました。APIは素晴らしいです。

import schedule
import time

def job():
    print("I'm working...")

schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
schedule.every(5).to(10).minutes.do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)
schedule.every().minute.at(":17").do(job)

while True:
    schedule.run_pending()
    time.sleep(1)

特にこのモジュールを使用するのに苦労しています。メインスレッドのブロックを解除する必要があります。スケジュールのドキュメントWebサイトのFAQを確認しましたが、提供された回避策がよくわかりませんでした。メインスレッドをブロックしない実用的な例をどこで見つけられるか知っていますか?
5Daydreams

1

私はTkinter after()メソッドを使用します。これは、「ゲームを盗む」ことはありません(以前に提示されたschedモジュールのように)。つまり、他のものを並行して実行できます。

import Tkinter

def do_something1():
  global n1
  n1 += 1
  if n1 == 6: # (Optional condition)
    print "* do_something1() is done *"; return
  # Do your stuff here
  # ...
  print "do_something1() "+str(n1)
  tk.after(1000, do_something1)

def do_something2(): 
  global n2
  n2 += 1
  if n2 == 6: # (Optional condition)
    print "* do_something2() is done *"; return
  # Do your stuff here
  # ...
  print "do_something2() "+str(n2)
  tk.after(500, do_something2)

tk = Tkinter.Tk(); 
n1 = 0; n2 = 0
do_something1()
do_something2()
tk.mainloop()

do_something1()そして、do_something2()並行してとどんな間隔の速度で実行することができます。ここでは、2番目の関数は2倍の速度で実行されます。また、どちらかの関数を終了する条件として単純なカウンターを使用したことにも注意してください。プログラムが終了するまでに実行する関数(たとえば、クロック)であれば、他の条件を使用することも、何も使用しないこともできます。


言い回しに注意してください:after並行して実行することはできません。Tkinterはシングルスレッドであり、一度に1つの処理しか実行できません。によってスケジュールされたものafterが実行されている場合、それは残りのコードと並行して実行されていません。do_something1do_something2が同時に実行されるようにスケジュールされている場合、それらは並列ではなく順次実行されます。
ブライアンオークリー

あなたのソリューションが行うすべてが使用することです@Apostolos のTkinterのの代わりにメインループをSCHEDそれは同じように正確に動作しますが、Tkinterのインターフェースが応答し続けることができますので、メインループ。他のものにtkinterを使用していない場合は、schedソリューションに関して何も変更されません。schedソリューションでは、間隔の異なる2つ以上のスケジュールされた関数を使用できます。これは、関数とまったく同じように機能します。
nosklo 2018年

いいえ、同じように機能しません。私はこれを説明しました。1つはプログラムを「ロック」します(つまり、フローを停止し、他に何もすることはできません。提案されている別の作業を開始することすらありません)。それが終了し、もう1つは手/フリーを解放します(つまり、それが始まった後、他のこと。それが終わるまで待つ必要はありません。これは大きな違いです。もしあなたが私が提示した方法を試したなら、あなたは自分で見たことがあるでしょう。私はあなたの方法を試してみました。私も試してみませんか?
Apostolos 2018年

1

これはMestreLionのコードに適合させたバージョンです。元の関数に加えて、このコード:

1)特定の時間にタイマーを起動するために使用されるfirst_intervalを追加します(呼び出し側はfirst_intervalを計算して渡す必要があります)

2)元のコードで競合状態を解決します。元のコードでは、制御スレッドが実行中のタイマーのキャンセルに失敗した場合(「タイマーを停止し、タイマーのアクションの実行をキャンセルします。これは、タイマーがまだ待機段階にある場合にのみ機能します。」https://から引用docs.python.org/2/library/threading.html)、タイマーは無限に実行されます。

class RepeatedTimer(object):
def __init__(self, first_interval, interval, func, *args, **kwargs):
    self.timer      = None
    self.first_interval = first_interval
    self.interval   = interval
    self.func   = func
    self.args       = args
    self.kwargs     = kwargs
    self.running = False
    self.is_started = False

def first_start(self):
    try:
        # no race-condition here because only control thread will call this method
        # if already started will not start again
        if not self.is_started:
            self.is_started = True
            self.timer = Timer(self.first_interval, self.run)
            self.running = True
            self.timer.start()
    except Exception as e:
        log_print(syslog.LOG_ERR, "timer first_start failed %s %s"%(e.message, traceback.format_exc()))
        raise

def run(self):
    # if not stopped start again
    if self.running:
        self.timer = Timer(self.interval, self.run)
        self.timer.start()
    self.func(*self.args, **self.kwargs)

def stop(self):
    # cancel current timer in case failed it's still OK
    # if already stopped doesn't matter to stop again
    if self.timer:
        self.timer.cancel()
    self.running = False

1

これは、受け入れられているソリューションよりもはるかに単純に見えます-私が考慮していない欠点がありますか?シンプルなコピーパスタを探してここに来て、がっかりしました。

import threading, time

def print_every_n_seconds(n=2):
    while True:
        print(time.ctime())
        time.sleep(n)

thread = threading.Thread(target=print_every_n_seconds, daemon=True)
thread.start()

非同期に出力します。

#Tue Oct 16 17:29:40 2018
#Tue Oct 16 17:29:42 2018
#Tue Oct 16 17:29:44 2018

実行中のタスクにかなりの時間がかかる場合、間隔は2秒+タスク時間になるため、正確なスケジューリングが必要な場合、これは適切ではありません。

なお、daemon=Trueフラグは、このスレッドがシャットダウンからアプリをブロックしないことを意味します。たとえばpytest、この広告が終了するのを待ってテストを実行した後、いつまでもハングする問題がありました。


いいえ、最初の日時のみを出力してから停止します...
Alex Poca

よろしいですか-コピーしてターミナルに貼り付けます。すぐに戻りますが、印刷はバックグラウンドで続行されます。
アダムヒューズ

ここに何か欠けているようです。test.pyにコードをコピーして貼り付け、python test.pyで実行します。Python2.7 では、認識されないdaemon = Trueを削除する必要があり、複数のプリントを読みました。Python3.8では、最初の印刷後に停止し、終了後にアクティブなプロセスはありません。daemon = Trueを削除すると、複数のプリントが読み込まれます...
Alex Poca

おかしいです-私はpython 3.6.10を使っています
アダム・ヒューズ

繰り返しますが、Python3.4.2(Debian GNU / Linux 8(jessie))では、daemon = Trueを削除して複数印刷できるようにする必要がありました。デーモン 私は、構文エラーが発生します。以前のPython2.7と3.8でのテストはUbuntu 19.10で行われていましたが、OSによってデーモンの扱いが異なるのでしょうか?
Alex Poca

0

これを使用して1時間あたり60のイベントを発生させ、ほとんどのイベントは1分後の同じ秒数で発生します。

import math
import time
import random

TICK = 60 # one minute tick size
TICK_TIMING = 59 # execute on 59th second of the tick
TICK_MINIMUM = 30 # minimum catch up tick size when lagging

def set_timing():

    now = time.time()
    elapsed = now - info['begin']
    minutes = math.floor(elapsed/TICK)
    tick_elapsed = now - info['completion_time']
    if (info['tick']+1) > minutes:
        wait = max(0,(TICK_TIMING-(time.time() % TICK)))
        print ('standard wait: %.2f' % wait)
        time.sleep(wait)
    elif tick_elapsed < TICK_MINIMUM:
        wait = TICK_MINIMUM-tick_elapsed
        print ('minimum wait: %.2f' % wait)
        time.sleep(wait)
    else:
        print ('skip set_timing(); no wait')
    drift = ((time.time() - info['begin']) - info['tick']*TICK -
        TICK_TIMING + info['begin']%TICK)
    print ('drift: %.6f' % drift)

info['tick'] = 0
info['begin'] = time.time()
info['completion_time'] = info['begin'] - TICK

while 1:

    set_timing()

    print('hello world')

    #random real world event
    time.sleep(random.random()*TICK_MINIMUM)

    info['tick'] += 1
    info['completion_time'] = time.time()

実際の条件によっては、長さの刻みが出る場合があります。

60,60,62,58,60,60,120,30,30,60,60,60,60,60...etc.

しかし、60分が終わると60ティックになります。そしてそれらのほとんどはあなたが好む分への正しいオフセットで発生します。

私のシステムでは、補正の必要が生じるまで、1/20秒未満の典型的なドリフトが発生します。

この方法の利点は、クロックドリフトの解決です。これは、ティックごとに1つのアイテムを追加するような場合に問題を引き起こす可能性があり、1時間あたり60のアイテムが追加されると予想します。ドリフトを考慮しないと、移動平均などの二次指標が過去のデータを深すぎると見なし、出力に欠陥が生じる可能性があります。


0

例:現在の現地時間を表示する

import datetime
import glib
import logger

def get_local_time():
    current_time = datetime.datetime.now().strftime("%H:%M")
    logger.info("get_local_time(): %s",current_time)
    return str(current_time)

def display_local_time():
    logger.info("Current time is: %s", get_local_time())
    return True

# call every minute
glib.timeout_add(60*1000, display_local_time)

0
    ''' tracking number of times it prints'''
import threading

global timeInterval
count=0
def printit():
  threading.Timer(timeInterval, printit).start()
  print( "Hello, World!")
  global count
  count=count+1
  print(count)
printit

if __name__ == "__main__":
    timeInterval= int(input('Enter Time in Seconds:'))
    printit()

ユーザー入力に基づいて、時間間隔ごとにそのメソッドを反復します。
raviGupta

0

これは、追加のライブラリを使用しない別のソリューションです。

def delay_until(condition_fn, interval_in_sec, timeout_in_sec):
    """Delay using a boolean callable function.

    `condition_fn` is invoked every `interval_in_sec` until `timeout_in_sec`.
    It can break early if condition is met.

    Args:
        condition_fn     - a callable boolean function
        interval_in_sec  - wait time between calling `condition_fn`
        timeout_in_sec   - maximum time to run

    Returns: None
    """
    start = last_call = time.time()
    while time.time() - start < timeout_in_sec:
        if (time.time() - last_call) > interval_in_sec:
            if condition_fn() is True:
                break
            last_call = time.time()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.