Bir işlevi her x saniyede bir art arda yürütmenin en iyi yolu nedir?


283

Her 20 saniyede bir Python'da sürekli olarak bir işlev yürütmek istiyorum (tıpkı bir NSTimer gibi) olarak Objective C ). Bu kod bir daemon olarak çalışır ve etkili bir şekilde bir cron kullanarak her dakika python betiğini çağırmaya benzer, ancak bunun kullanıcı tarafından ayarlanmasını gerektirmez.

In Python uygulanan bir cron hakkında bu soruya , solüsyon etkili sadece görünen uyku () x saniye boyunca. Böyle gelişmiş bir işleve ihtiyacım yok, belki böyle bir şey işe yarayabilir

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

Bu kodla ilgili öngörülebilir sorunlar var mı?


83
Bilgiçliksel bir nokta, ancak kritik olabilir, kodun üstündeki kodunuz her 60 saniyede bir yürütülmez, yürütmeler arasında 60 saniyelik bir boşluk bırakır. Sadece 60 saniyede bir, yürütülen kodunuz hiç zaman almazsa olur.
Simon

4
ayrıca time.sleep(60)daha erken ve daha sonra geri dönebilir
jfs

5
Hala merak ediyorum: Bu kod ile öngörülebilir herhangi bir sorun var mı?
Muz

1
"Öngörülebilir sorun" sadece time.sleep (60) kullanarak saatte 60 yineleme bekleyemezsiniz. Dolayısıyla, yineleme başına bir öğe ekliyorsanız ve ayarlanan uzunluk listesini tutuyorsanız ... bu listenin ortalaması tutarlı bir "süreyi" temsil etmez; "hareketli ortalama" gibi işlevler, göstergenizi bozacak çok eski veri noktalarını referans gösterebilir.
litepresence

2
@ Banana Evet, betiğiniz her 60 saniyede bir TAMAMEN yürütülmediği için herhangi bir sorun bekleyebilirsiniz. Örneğin. Video akışlarını bölmek ve yüklemek için böyle bir şey yapmaya başladım ve döngü içinde veri işlerken medya kuyruğu arabelleğe alındığı için 5-10 ~ saniye daha uzun kenarları elde ettim. Verilerinize bağlıdır. Eğer fonksiyon bir çeşit basit bekçi köpeği ise, bu sizi uyarır, örneğin, diskiniz dolduğunda, bununla ilgili hiç problem yaşamamalısınız. tamamen havaya uçuruldu x
DGoiko

Yanıtlar:


229

Programınızda zaten bir olay döngüsü yoksa , genel amaçlı bir olay zamanlayıcı uygulayan sched modülünü kullanın .

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()

Zaten böyle bir olay döngü kitaplığı kullanıyorsanız asyncio, trio, tkinter, PyQt5, gobject, kivy, ve diğerleri - sadece yerine, mevcut olay döngü kütüphanenin yöntemleri kullanarak görev zamanlama.


16
Zamanlama modülü, bir süre sonra çalışacak zamanlama işlevlerine yöneliktir, time.sleep () kullanmadan her x saniyede bir işlev çağrısını tekrarlamak için nasıl kullanılır?
Baishampayan Ghose

2
@Baishampayan: Yeni bir koşu programlayın.
nosklo

3
O zaman en apscheduler packages.python.org/APScheduler da bu noktada söz almalısınız.
Daniel F

6
not: bu sürüm sürüklenebilir. Bunu enterabs()önlemek için kullanabilirsiniz . İşte karşılaştırma için bir sigara sürüklenen versiyonu .
jfs

8
@JavaSa: çünkü "eşyalarınızı yapın" anlık değildir ve hatalar time.sleepburada birikebilir. "her X saniyede bir çalıştır" ve "tekrar tekrar ~ X saniyede bir gecikmeyle yürüt" aynı değildir. Ayrıca bu yoruma
jfs

180

Zaman döngünüzü sistem saatine şu şekilde kilitleyin:

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

22
+1. sizinkiler ve twistedcevap her xsaniye bir işlevi çalıştıran tek cevaplardır . Geri kalanı işlevi xher çağrıdan sonra birkaç saniye gecikme ile yürütür .
jfs

13
Eğer bir saniyeden daha uzun süren bir kod ekleyecekseniz, zamanlamayı dışarı atar ve geride kalmaya başlar .. Bu durumda kabul edilen cevap doğrudur ... Herkes basit bir yazdırma komutunu döngüye sokabilir ve gecikmeden her saniyede ...
Angry 84

5
Tercihim from time import time, sleepçünkü varoluşsal etkileri;)
Will

14
Fevkalade çalışır. starttimeBelirli bir zamana senkronize ederek başlıyorsanız, çıkarmanıza gerek yoktur : time.sleep(60 - time.time() % 60)benim için iyi çalışıyor. Ben kullandım time.sleep(1200 - time.time() % 1200)ve :00 :20 :40tam olarak istediğim gibi, bana günlükleri verir .
TemporalWolf

2
@AntonSchigur birden fazla yinelemeden sonra kaymayı önlemek için. Tek bir yineleme bağlı olarak biraz er ya da geç başlayabilir sleep(), timer()hassas ve döngü gövdesini yürütmek ama ortalama tekrarlamalar her zaman (bazı atlandı olsalar dahi) aralık sınırları üzerinde meydana ne kadar sürdüğünü: while keep_doing_it(): sleep(interval - timer() % interval). Sadece ile kıyaslayın while keep_doing_it(): sleep(interval)hatalar Birkaç tekrar birikmeye nerelerde.
jfs

71

Reaktör Kalıbını uygulayan bir Python ağ kütüphanesi olan Twisted'ı düşünebilirsiniz .

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)" muhtemelen işe yarayacak olsa da Twisted muhtemelen sonunda ihtiyaç duyacağınız özelliklerin çoğunu (bobince'nin işaret ettiği gibi daemonization, günlüğe kaydetme veya istisna işleme) uygular ve muhtemelen daha sağlam bir çözüm olacaktır.


Büyük cevap da, sürüklenme olmadan çok doğru. Acaba bu görevi yerine getirmek için beklerken CPU da uyku koyar mı (aka meşgul bekleyen değil)?
smoothware

1
milisaniye seviyesinde sürükleniyor
Derek Eden

"Milisaniye seviyesindeki sapmalar" ne anlama geliyor?
Jean-Paul Calderone

67

Fonksiyonunuzu periyodik olarak yürütmenin engellenmeyen bir yolunu istiyorsanız, sonsuz döngüyü engelleme yerine, dişli bir zamanlayıcı kullanırım. Bu şekilde kodunuz çalışmaya devam edebilir ve diğer görevleri gerçekleştirebilir ve yine de her n saniyede bir işlev çağrılır. Uzun, CPU / Disk / Ağ yoğun görevlerde ilerleme bilgisini yazdırmak için bu tekniği çok kullanıyorum.

Start () ve stop () kontrolü ile benzer bir soruda gönderdiğim kod:

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

Kullanımı:

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!

Özellikleri:

  • Yalnızca standart kitaplık, harici bağımlılık yok
  • start()ve stop()zamanlayıcı zaten başlamış / durmuş olsa bile birden çok kez aramak güvenlidir
  • çağrılacak fonksiyonun konumsal ve adlandırılmış argümanları olabilir
  • İstediğiniz zaman değiştirebilirsiniz interval, bir sonraki çalıştırmadan sonra etkili olacaktır. Aynı için args, kwargsve hatta function!

Bu çözüm zamanla kayıyor gibi görünüyor; Sürüklemeden fonksiyonu her n saniyede bir çağırmayı amaçlayan bir sürüme ihtiyacım vardı. Ayrı bir soruya bir güncelleme göndereceğim.
eraoul

Gelen def _run(self)seni dememizin etrafında başımı sarmak için çalışıyorum self.start()önce self.function(). Detaylandırabilir misin? Ben her zaman yeni bir iş parçacığının spin kadar start()ilk arayarak self.is_runningher zaman olacağını düşünürdüm False.
Rich Episcopo

1
Bence onun dibine geldim. @ MestreLion'un çözümü her xsaniye (örneğin, t = 0, t = 1x, t = 2x, t = 3x, ...) bir fonksiyon çalıştırır; burada orijinal posterlerde örnek kod, aralarında x saniye aralığına sahip bir fonksiyon çalıştırır . Ayrıca, bu çözüm yürütmek intervaliçin gereken süreden daha kısa ise bir hata var inanıyorum function. Bu durumda, fonksiyonun self._timerüzerine yazılır start.
Rich Episcopo

Evet, @RichieEpiscopo, .function()after çağrısı .start()işlevi t = 0'da çalıştırmaktır. Ve functiondaha uzun sürerse bir sorun olacağını düşünmüyorum interval, ancak evet kodda bazı yarış koşulları olabilir.
MestreLion

Bu, engellemediğim tek yol. Teşekkürler.
backslashN

35

Daha kolay olduğuna inanıyorum:

import time

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

while True:
    executeSomething()

Bu şekilde kodunuz yürütülür, sonra 60 saniye bekler, sonra tekrar yürütür, bekler, yürütür, vb ... İşleri karmaşıklaştırmaya gerek yok: D


True anahtar kelimesi büyük harf olmalıdır
Sean Cain

38
Aslında bu cevap değildir: zaman uykusu () sadece her yürütmeden sonra X saniye beklemek için kullanılabilir. Örneğin, işlevinizin yürütülmesi 0,5 saniye sürüyorsa ve time.sleep (1) kullanıyorsanız, işlevinizin 1 değil 1.5 saniyede bir çalıştığı anlamına gelir. Y modunun çalıştığından emin olmak için diğer modülleri ve / veya konuları kullanmalısınız her X saniyede bir.
kommradHomer

1
@kommradHomer: Dave Rove cevabı sen göstermektedir edebilirsiniz kullanmak time.sleep()her X saniyede koşmak bir şey
jfs

2
Kanımca kod döngü time.sleep()içinde şöyle çağırmalıdır while True:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
Leonard 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)

Kalan kodunuzu engellemeden bunu yapmak istiyorsanız, bunu kendi iş parçacığında çalışmasına izin vermek için kullanabilirsiniz:

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

Bu çözüm, diğer çözümlerde nadiren bulunan çeşitli özellikleri birleştirir:

  • İstisna yönetimi: Bu seviyede mümkün olduğunca istisnalar uygun şekilde ele alınır, yani programımızı iptal etmeden hata ayıklama amacıyla günlüğe kaydedilir.
  • Zincirleme yok: Birçok cevapta bulduğunuz ortak zincir benzeri uygulama (bir sonraki olayı planlamak için), programlama mekanizması ( threading.Timerveya herhangi bir şey) içinde bir şey ters giderse , bu zinciri sonlandıracak şekilde kırılgandır . Sorunun nedeni önceden belirlenmiş olsa bile, başka yürütme olmayacaktır. Basit bir döngü ve basitle beklemek sleep()kıyaslandığında çok daha sağlamdır.
  • Kayma yok: Çözümüm, kaç kez çalışacağını tam olarak takip ediyor. Yürütme süresine bağlı olarak sürüklenme olmaz (diğer birçok çözümde olduğu gibi).
  • Atlama: Bir yürütme çok fazla zaman alırsa çözümüm görevleri atlayacaktır (örneğin her beş saniyede bir X yapın, ancak X 6 saniye sürdü). Bu standart cron davranışıdır (ve iyi bir nedenden dolayı). Diğer birçok çözüm daha sonra görevi üst üste birkaç kez herhangi bir gecikme olmadan yürütür. Çoğu durumda (örn. Temizleme görevleri) bu istenmez. O takdirde edilir diledi, sadece kullanım next_time += delayyerine.

2
sürüklenmediği için en iyi cevap.
Sebastian Stark

1
@PirateApp Bunu farklı bir iş parçacığında yaparım. Sen olabilir aynı iş parçacığı bunu ancak o zaman bir yorum için yol çok karmaşıktır kendi zamanlama sisteminin programlanması sonunda.
Alfe

1
Python'da, GIL sayesinde, iki iş parçacığında değişkenlere erişmek tamamen güvenlidir. Ve sadece iki iş parçacığında okumak asla sorun olmamalı (diğer iş parçacıkları ortamlarında da olmamalıdır). GIL içermeyen bir sistemde (ör. Java, C ++ vb.) Yalnızca iki farklı iş parçacığından yazmak için bazı açık senkronizasyonlar gerekir.
Alfe

1
@ user50473 Daha fazla bilgi olmadan önce göreve iş parçacığı tarafından yaklaşacağım. Bir iş parçacığı şimdi ve sonra verileri okur ve tekrar yapma zamanı gelene kadar uyur. Yukarıdaki çözüm elbette bunu yapmak için kullanılabilir. Ama farklı bir yoldan gitmek için bir sürü neden hayal edebiliyorum. Çok iyi şanslar :)
Alfe

1
Uyku, iş parçacığı ile değiştirilebilir. Uygulama çıkışında daha duyarlı olmak için zaman aşımı ile bekleyin. stackoverflow.com/questions/29082268/…
themadmax

20

İşte MestreLion'un kodunda zaman içinde sürüklenmeyi önleyen bir güncelleme.

Buradaki RepeatedTimer sınıfı, OP tarafından istendiği gibi verilen her "aralık" saniyede bir işlevi çağırır; zamanlama, işlevin yürütülmesi için geçen süreye bağlı değildir. Harici kütüphane bağımlılıkları olmadığı için bu çözümü seviyorum; bu sadece saf bir piton.

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

Örnek kullanım (MestreLion'un cevabından kopyalandı):

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

Bir süre önce benzer bir sorunla karşılaştım. Olabilir http://cronus.readthedocs.org yardımcı olabilecek?

V0.2 için aşağıdaki snippet çalışır

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

Bu ve cron arasındaki temel fark, bir istisnanın cini iyi için öldürecek olmasıdır. Bir istisna yakalayıcı ve kaydedici ile sarmak isteyebilirsiniz.


4

Bir olası cevap:

import time
t=time.time()

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

1
Bu, bu nedenle çok kötü beklemekle meşgul.
Alfe

Engelleme yapmayan bir zamanlayıcı arayan biri için iyi bir çözüm.
Noel

3

Ben kullanarak sona erdi zamanlama modülü. API güzel.

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)

Özellikle bu modülü kullanmaya çalışırken zorlanıyorum, ana iş parçacığının engelini kaldırmam gerekiyor, programın dokümantasyon web sitesindeki SSS'yi kontrol ettim, ancak gerçekten sağlanan geçici çözümü anlamadım. Herkes ana iş parçacığı engellemeyen çalışan bir örnek nerede bulabilirim biliyor mu?
5Daydreams

1

Ben "oyunu çalmak" ( daha önce sunulan zamanlama modülü gibi) değil Tkinter after () yöntemini kullanın , yani diğer şeylerin paralel olarak çalışmasına izin verir:

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()ve do_something2()paralel ve herhangi bir aralık hızında çalışabilir. Burada, ikincisi iki kat daha hızlı yürütülecektir.Ayrıca, her iki işlevi sonlandırmak için bir koşul olarak basit bir sayaç kullandığımı da unutmayın. Program sona erene kadar çalıştırılacak bir işlev varsa (örneğin bir saat) istediğiniz başka herhangi bir kongreyi kullanabilirsiniz.


İfadelerinize dikkat edin: afterşeylerin paralel çalışmasına izin vermez. Tkinter tek iş parçacıklıdır ve her seferinde sadece bir şey yapabilir. Tarafından planlanan bir şey afterçalışıyorsa, kodun geri kalanıyla paralel olarak çalışmaz. Her ikisi de do_something1ve do_something2aynı anda çalışması planlanıyorsa, paralel değil sıralı olarak çalışırlar.
Bryan Oakley

Çözümünüz yapar tüm kullanmaktır @Apostolos Tkinter yerine mainloop sched aynı şekilde tam olarak çalışır fakat Tkinter arayüzleri yanıt devam etmesini sağlar, böylece mainloop. Tkinter'ı başka şeyler için kullanmıyorsanız, zamanlama çözümü ile ilgili hiçbir şey değişmez. Çözümde farklı aralıklarla iki veya daha fazla zamanlanmış işlev kullanabilirsiniz schedve bu çözüm tamamen sizinkiyle aynı şekilde çalışır.
nosklo

Hayır, aynı şekilde çalışmaz. Bunu açıkladım. Biri programı "kilitler" (yani akışı durdurur, başka bir şey yapamazsınız - önerdiğiniz gibi başka bir scecduled iş bile başlatmazsınız) ve diğeri ellerinizi serbest bırakabilir / serbest bırakabilir (yani Başladıktan sonra başka şeyler ... Tamamlanana kadar beklemek zorunda değilsiniz. Bu çok büyük bir fark. Eğer sunduğum yöntemi deneseydiniz, kendiniz görürdünüz. Sizinkini denedim. Neden yapmıyorsunuz benim de denemek ister misiniz?
Apostolos

1

İşte MestreLion koduna uyarlanmış bir versiyon. Orijinal işleve ek olarak, bu kod:

1) zamanlayıcıyı belirli bir zamanda tetiklemek için kullanılan first_interval ekleyin (arayan ilk_interval değerini hesaplamalı ve içeri aktarmalıdır)

2) Bir yarış koşulunu orijinal kodda çözer. Orijinal kodda, kontrol iş parçacığı çalışan zamanlayıcıyı iptal edemediyse ("Zamanlayıcıyı durdurun ve zamanlayıcının işleminin yürütülmesini iptal edin. Bu yalnızca zamanlayıcı hala bekleme aşamasındaysa çalışır." Https: // docs.python.org/2/library/threading.html ), zamanlayıcı sürekli olarak çalışır.

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

Bu, kabul edilen çözümden çok daha basit görünüyor - düşünmediğim eksiklikler var mı? Buraya bazı ölü basit kopya makarna arıyor geldi ve hayal kırıklığına uğradım.

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()

Hangi zaman uyumsuz çıktı.

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

Çalıştırılan görev kayda değer miktarda zaman alırsa, aralığın 2 saniye + görev süresi haline gelmesi anlamında sürüklenir, bu nedenle kesin zamanlamaya ihtiyacınız varsa bu sizin için değildir.

İşaretin, daemon=Truebu iş parçacığının uygulamanın kapanmasını engellemeyeceği anlamına geldiğini unutmayın . Örneğin, pytesttestlerin yürütüldükten sonra bu sonun durmasını beklerken süresiz olarak nerede duracağı sorunu vardı .


Hayır, yalnızca ilk tarih saatini yazdırıyor ve sonra duruyor ...
Alex Poca

Emin misiniz - sadece kopyalayıp terminale yapıştırdım. Hemen geri dönüyor, ancak çıktı benim için arka planda devam ediyor.
Adam Hughes

Görünüşe göre burada bir şey eksik. Kodu test.py içine kopyaladım / yapıştırdım ve python test.py ile çalıştım . Python2.7 ile daemon = True tanınmayan kaldırmak gerekir ve birden fazla baskı okuyun. Python3.8 ile ilk baskıdan sonra durur ve bitiminden sonra hiçbir işlem aktif olmaz. Daemon kaldırılıyor = Doğru Birden fazla baskı okudum ...
Alex Poca

hmm garip - Python 3.6.10'dayım ama bunun neden önemli olduğunu bilmiyorum
Adam Hughes

Tekrar: Python3.4.2 (Debian GNU / Linux 8 (jessie)), çoklu baskı yapabilmesi için daemon = True öğesini kaldırmak zorunda kaldı . Daemon ile bir sözdizimi hatası alıyorum. Python2.7 ve 3.8 ile yapılan önceki testler Ubuntu 1910'da yapıldı. Daemon OS'ye göre farklı muamele görebilir mi?
Alex Poca

0

Bunu, tüm dakikalardan sonra aynı sayıda saniyede gerçekleşen çoğu olayla saatte 60 olaya neden olmak için kullanıyorum:

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()

Gerçek koşullara bağlı olarak uzunluk keneleri alabilirsiniz:

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

ama 60 dakikanın sonunda 60 keneniz olacak; ve çoğu tercih ettiğiniz dakikaya kadar doğru ofsette gerçekleşir.

Sistemimde düzeltme ihtiyacı ortaya çıkana kadar saniyenin 1 / 20'sinden az sapması oluyor.

Bu yöntemin avantajı, saat kaymasının çözümlenmesidir; kene başına bir öğe eklemek gibi bir şey yapıyorsanız ve saat başına 60 öğe eklenmesini beklerseniz sorunlara neden olabilir. Kaymayı hesaba katmamak, hareketli ortalamalar gibi ikincil göstergelerin verileri geçmişin çok derinlerinde değerlendirmesine neden olarak hatalı çıktıya neden olabilir.


0

ör. Geçerli yerel saati göster

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()

Kullanıcı girdisine dayanarak, bu yöntemi her zaman aralığında yineleyecektir.
raviGupta

0

İşte ekstra libaries kullanmadan başka bir çözüm.

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()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.