x 초마다 함수를 반복적으로 실행하는 가장 좋은 방법은 무엇입니까?


283

파이썬에서 60 초마다 반복적으로 함수를 반복하고 싶습니다 ( Objective C 의 NSTimer 와 마찬가지로 ). 이 코드는 데몬으로 실행되며 크론을 사용하여 매분마다 파이썬 스크립트를 호출하는 것과 비슷하지만 사용자가 설정하지 않아도됩니다.

에서 파이썬으로 구현 된 크론에 대한이 질문에 솔루션을 효과적으로 단지에 나타나는 수면 () x 초합니다. 나는 그러한 고급 기능이 필요하지 않으므로 아마도 이와 같은 것이 작동 할 것입니다.

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

이 코드에 예측 가능한 문제가 있습니까?


83
pedantic point,하지만 중요한 것은 코드 위의 코드가 60 초마다 실행되지 않고 실행 사이에 60 초 간격을 두는 것입니다. 실행 된 코드가 전혀 시간이 걸리지 않으면 60 초마다 발생합니다.
Simon

4
또한 time.sleep(60)이전과 이후 모두 반환 될 수 있습니다
jfs

5
여전히 궁금합니다. 이 코드에 예측 가능한 문제가 있습니까?
바나나

1
"예측 가능한 문제"는 time.sleep (60)을 사용하여 시간당 60 회 반복을 기대할 수 없다는 것입니다. 따라서 반복마다 하나의 항목을 추가하고 설정된 길이의 목록을 유지하는 경우 해당 목록의 평균은 일관된 "기간"을 나타내지 않습니다. "이동 평균"과 같은 기능은 너무 오래된 데이터 포인트를 참조 할 수 있으므로 표시가 왜곡됩니다.
litepresence

2
@Banana 예, 스크립트가 60 초마다 정확히 실행되지 않기 때문에 어떤 문제가 발생할 수 있습니다. 예를 들어. 비디오 스트림과 업로드를 분할하기 위해 이와 같은 작업을 시작했으며 루프 내부의 데이터를 처리하는 동안 미디어 큐가 버퍼링되기 때문에 5-10 ~ 더 긴 스트림을 얻었습니다. 데이터에 따라 다릅니다. 예를 들어, 디스크가 가득 찼을 때와 같이 경고 기능을하는 간단한 감시 장치 인 경우에는 전혀 문제가 없을 것입니다. 완전하게 폭파 x
DGoiko

답변:


229

프로그램에 이벤트 루프가없는 경우, 범용 이벤트 스케줄러를 구현하는 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()

이미 같은 이벤트 루프 라이브러리를 사용하는 경우 asyncio, trio, tkinter, PyQt5, gobject, kivy, 그리고 많은 다른 - 단지 대신, 기존의 이벤트 루프 라이브러리의 방법을 사용하여 작업을 예약.


16
sched 모듈은 일정 시간 후에 함수가 실행되도록 예약하는 데 사용되며 time.sleep ()을 사용하지 않고 x 초마다 함수 호출을 반복하는 데 어떻게 사용합니까?
Baishampayan Ghose

2
@ Baishampayan : 그냥 새로운 달리기를 예약하십시오.
nosklo

3
그런 다음에 apscheduler packages.python.org/APScheduler는 이 시점에서 언급을 받아야합니다.
Daniel F

6
참고 :이 버전은 표류 할 수 있습니다. enterabs()피하기 위해 사용할 수 있습니다 . 여기 비교 비 표류 버전 .
jfs

8
@JavaSa : "당신의 작업을 수행하십시오" 는 즉각적이지 않으며 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

13
1 초 이상 걸리는 코드를 추가 할 위치가 있으면 시간이 초과되어 뒤처지기 시작합니다.이 경우 허용되는 대답은 정확합니다 ... 누구나 간단한 인쇄 명령을 반복 할 수 있습니다 그리고는 지체없이 모든 초 ... 실행이
84 화가

5
나는 from time import time, sleep실존 적 의미 때문에 선호 한다;)
Will

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 Pattern 을 구현하는 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 : sleep (60)"은 아마도 작동하지만 Twisted는 아마도 여러분이 궁극적으로 필요로하는 많은 기능 (bobince가 지적한 데몬 처리, 로깅 또는 예외 처리)을 이미 구현하고 있으며보다 강력한 솔루션 일 것입니다


드리프트 없이도 매우 정확한 응답. 이것이 작업 실행을 기다리는 동안 (일부 사용 중이 아닌) CPU를 잠자기 상태로 만드는지 궁금합니다.
smoothware

1
이것은 밀리 초 수준으로 표류합니다
Derek Eden

"밀리 초 수준으로 드리프트"란 무엇을 의미합니까?
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언제든지 변경할 수 있으며 다음 실행 후 효과적입니다. 동일에 args, kwargs심지어 function!

이 솔루션은 시간이 지남에 따라 표류하는 것처럼 보입니다. 드리프트없이 n 초마다 함수를 호출하는 버전이 필요했습니다. 별도의 질문으로 업데이트를 게시하겠습니다.
eraoul

에서 def _run(self)당신이 부르는 이유 주위에 내 머리를 정리하려고 self.start()하기 전에 self.function(). 정교하게 할 수 있습니까? start()먼저 호출 self.is_running하면 항상 그렇다고 생각하고 False항상 새 스레드를 시작합니다.
Rich Episcopo

1
나는 그것의 바닥에 도착했다고 생각합니다. @MestreLion의 솔루션은 매초마다 함수를 실행합니다 x(예 : t = 0, t = 1x, t = 2x, t = 3x, ...). 원본 포스터에서 샘플 코드는 x 초 간격 의 함수를 실행합니다 . 또한이 솔루션 intervalfunction실행 하는 데 걸리는 시간보다 짧은 경우 버그가 있다고 생각 합니다. 이 경우 함수 self._timer에서 덮어 씁니다 start.
Rich Episcopo

예, @RichieEpiscopo, .function()이후에 대한 호출 .start()은 t = 0에서 함수를 실행하는 것입니다. 그리고 function보다 오래 걸리면 문제가 될 것이라고 생각하지 않지만 interval코드에 경마 조건이있을 수 있습니다.
MestreLion

이것이 내가 얻을 수있는 유일한 비 차단 방법입니다. 감사.
backslashN

35

내가 믿는 더 쉬운 방법은 다음과 같습니다.

import time

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

while True:
    executeSomething()

이렇게하면 코드가 실행 된 다음 60 초 동안 기다린 다음 다시 실행, 대기, 실행 등을 복잡하게 할 필요가 없습니다.


키워드 True는 대문자 여야합니다
Sean Cain

38
실제로 이것은 답이 아닙니다 : time sleep ()은 매 실행 후 X 초 동안 만 사용할 수 있습니다. 예를 들어 함수를 실행하는 데 0.5 초가 걸리고 time.sleep (1)을 사용하는 경우 함수가 1이 아니라 1.5 초마다 실행됨을 의미합니다. 다른 모듈 및 / 또는 스레드를 사용하여 Y 시간 동안 작동하는지 확인하십시오. 매 X 초마다.
kommradHomer

1
@kommradHomer : Dave Rove의 답변에 따르면 매 X 초마다 무언가를 실행할 있음을 알 있습니다.time.sleep()
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()가 훨씬 강력합니다.
  • 표류 없음 : 내 솔루션은 실행 예정 시간을 정확하게 추적합니다. 실행 시간에 따라 다른 많은 솔루션 에서처럼 드리프트가 없습니다.
  • 건너 뛰기 : 한 번의 실행에 너무 많은 시간이 걸리면 솔루션이 작업을 건너 뜁니다 (예 : 5 초마다 X를 수행하지만 X는 6 초가 걸렸습니다). 이것은 표준 크론 동작입니다. 다른 많은 솔루션은 지연없이 작업을 여러 번 연속해서 실행합니다. 대부분의 경우 (예 : 정리 작업) 이것은 바람직하지 않습니다. 이 경우 되고 싶다고, 단순히 사용하는 next_time += delay대신.

2
표류하지 않는 것이 가장 좋습니다.
Sebastian Stark

1
@PirateApp 다른 스레드 에서이 작업을 수행합니다. 당신은 할 수 동일한 스레드에서 할하지만 당신은 논평을 너무 복잡 자신의 스케줄링 시스템을 프로그래밍 끝.
Alfe

1
파이썬에서는 GIL 덕분에 두 스레드에서 변수에 액세스하는 것이 완벽하게 안전합니다. 그리고 두 스레드에서 읽는 것만으로는 문제가되지 않아야합니다 (다른 스레드 환경에서도). GIL이없는 시스템 (예 : Java, C ++ 등)에서 서로 다른 두 스레드에서 쓰려면 명시적인 동기화가 필요합니다.
Alfe

1
@ user50473 추가 정보가 없으면 먼저 스레드 쪽에서 작업에 접근합니다. 한 스레드는 이제 데이터를 읽은 다음 다시 할 때까지 대기합니다. 위의 솔루션은 물론 이것을 수행하는 데 사용될 수 있습니다. 그러나 나는 다른 길을 갈 많은 이유를 상상할 수 있었다. 행운을 빕니다 :)
Alfe

1
스레딩을 통해 절전 모드를 대체 할 수 있습니다. 응용 프로그램 종료시 시간 초과가 발생하면 이벤트 대기 시간이 단축됩니다. stackoverflow.com/questions/29082268/…
themadmax

20

다음은 시간이 지남에 따라 드리핑을 피하는 MestreLion의 코드 업데이트입니다.

여기서 RepeatedTimer 클래스는 OP에서 요청한대로 "간격"초마다 지정된 함수를 호출합니다. 스케줄은 함수를 실행하는 데 걸리는 시간에 의존하지 않습니다. 외부 라이브러리 종속성이 없기 때문에이 솔루션을 좋아합니다. 이것은 순수한 파이썬입니다.

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

가능한 답변 :

import time
t=time.time()

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

1
이것은 매우 나쁜 기다리는 바쁘다.
Alfe

비 차단 타이머를 찾는 사람에게 적합한 솔루션입니다.
Noel

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)

특히이 모듈을 사용하려고하는데 어려움을 겪고 있습니다. 주 스레드를 차단 해제해야합니다. 스케줄의 문서 웹 사이트에서 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()병렬로 어떤 구간 속도에서 실행할 수 있습니다. 여기서 두 번째는 두 배 빠른 속도로 실행됩니다. 또한 두 함수 중 하나를 종료하기위한 조건으로 간단한 카운터를 사용했습니다. 프로그램이 종료 될 때까지 어떤 기능 (예 : 시계)을 실행하든 원하는 다른 조건을 사용하거나 사용하지 않을 수 있습니다.


당신의 말에주의하십시오 : after사물을 병렬로 실행할 수 없습니다. Tkinter는 단일 스레드이며 한 번에 한 가지 작업 만 수행 할 수 있습니다. 예약 된 항목 after이 실행중인 경우 나머지 코드와 병렬로 실행되지 않습니다. 두 경우 do_something1와는 do_something2같은 시간에 실행되도록 예약, 그들은하지 병렬로, 순차적으로 실행됩니다.
Bryan Oakley

@Apostolos의 모든 솔루션은 sched mainloop 대신 tkinter mainloop를 사용하는 것이므로 정확히 동일한 방식으로 작동하지만 tkinter 인터페이스가 계속 응답 할 수 있습니다. 다른 것들에 tkinter를 사용하지 않으면 sched 솔루션과 관련하여 아무것도 변경되지 않습니다. 솔루션 에서 다른 간격으로 둘 이상의 예약 된 기능을 사용할 수 있으며 사용자의 기능과 정확히 동일하게 작동합니다. sched
nosklo

아니요, 같은 방식으로 작동하지 않습니다. 나는 이것을 설명했다. 하나는 프로그램을 "잠그고"(즉, 흐름을 멈추고, 다른 어떤 것도 할 수 없습니다-당신이 제안한대로 다른 작업을 시작하지 않더라도) 다른 하나는 핸즈프리를 자유롭게 할 수 있습니다 (즉, 할 수 있습니다) 그것이 시작된 후에 다른 것들이 끝날 때까지 기다릴 필요가 없습니다. 이것은 큰 차이입니다. 내가 제시 한 방법을 시도했다면, 당신은 스스로를 보았을 것입니다. 나는 당신을 시도했습니다.
나도

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

확실합니까-터미널에 복사하여 붙여 넣었습니다. 그것은 즉시 돌아 오지만 인쇄물은 나를 위해 백그라운드에서 계속됩니다.
Adam Hughes

여기에 뭔가 빠진 것 같습니다. test.py 코드를 복사하여 붙여 넣은 다음 python test.py로 실행 합니다. Python2.7을 사용하면 daemon = True 를 제거해야 합니다. 인식되지 않고 여러 번 인쇄했습니다. Python3.8에서는 첫 번째 인쇄 후에 중지되고 종료 후에는 프로세스가 활성화되지 않습니다. daemon 제거 = 진정한 여러 장을 읽었습니다 ...
Alex Poca

흠 이상한-나는 파이썬 3.6.10에 있지만 왜 그것이 중요한지 모르겠다
Adam Hughes

다시 한 번 : Python3.4.2 (Debian GNU / Linux 8 (jessie))는 daemon = True 를 제거하여 다중 인쇄 할 수있었습니다. 로 데몬 나는 구문 오류가 발생합니다. Python2.7 및 3.8의 이전 테스트는 Ubuntu 19.10에서 수행되었습니다. OS에 따라 데몬이 다르게 처리 될 수 있습니까?
Alex Poca

0

나는 이것을 사용하여 시간당 60 개의 이벤트를 발생시키고 대부분의 이벤트는 전체 분 후에 동일한 초 수에서 발생합니다.

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 초의 전형적인 드리프트를 얻습니다.

이 방법의 장점은 클럭 드리프트의 해상도입니다. 틱당 하나의 항목을 추가하는 것과 같은 작업을 수행하고 시간당 60 개의 항목이 추가되는 경우 문제가 발생할 수 있습니다. 드리프트를 설명하지 않으면 이동 평균과 같은 2 차 표시가 데이터를 너무 깊게 고려하여 출력이 잘못 될 수 있습니다.


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.