प्रत्येक एक्स सेकंड में किसी फ़ंक्शन को बार-बार निष्पादित करने का सबसे अच्छा तरीका क्या है?


282

मैं पायथन में हर 60 सेकंड में एक फ़ंक्शन को बार-बार निष्पादित करना चाहता हूं (बस उद्देश्य सी में एक NSTimer की तरह )। यह कोड एक डेमॉन के रूप में चलेगा और प्रभावी रूप से क्रोन का उपयोग करके हर मिनट अजगर स्क्रिप्ट को कॉल करने जैसा है, लेकिन उपयोगकर्ता द्वारा स्थापित किए जाने की आवश्यकता के बिना।

पायथन में लागू एक क्रोन के बारे में इस सवाल में , समाधान x सेकंड के लिए प्रभावी रूप से सिर्फ नींद () के लिए प्रकट होता है । मुझे इस तरह की उन्नत कार्यक्षमता की आवश्यकता नहीं है, इसलिए शायद ऐसा कुछ काम करेगा

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

क्या इस कोड के साथ कोई समस्या नहीं है?


83
एक पांडित्यपूर्ण बिंदु, लेकिन यह महत्वपूर्ण हो सकता है, आपके कोड के ऊपर कोड हर 60 सेकंड में निष्पादित नहीं होता है जो निष्पादन के बीच 60 सेकंड का अंतर रखता है। यह केवल हर 60 सेकंड में होता है यदि आपका निष्पादित कोड बिल्कुल भी समय नहीं लेता है।
सिमोन

4
यह भी time.sleep(60)दोनों पहले और बाद में वापस आ सकते हैं
JFS

5
मैं अभी भी सोच रहा हूं: क्या इस कोड के साथ कोई समस्या नहीं है?
केले

1
"दूरदर्शी समस्या" यह है कि आप केवल time.sleep (60) का उपयोग करके प्रति घंटे 60 पुनरावृत्तियों की उम्मीद नहीं कर सकते। इसलिए यदि आप प्रति आइटम एक आइटम जोड़ रहे हैं और निर्धारित लंबाई की एक सूची रख रहे हैं ... उस सूची का औसत समय की एक सुसंगत "अवधि" का प्रतिनिधित्व नहीं करेगा; इसलिए "चलती औसत" जैसे फ़ंक्शन डेटा बिंदुओं को संदर्भित कर सकते हैं जो बहुत पुराने हैं, जो आपके संकेत को विकृत करेगा।
litepresence

2
@ बाना हां, आप किसी भी समस्या की वजह से उम्मीद कर सकते हैं क्योंकि आपकी स्क्रिप्ट को हर 60 सेकंड में निष्पादित नहीं किया जाता है। उदाहरण के लिए। मैंने वीडियो स्ट्रीम और upload'em को विभाजित करने के लिए ऐसा कुछ करना शुरू कर दिया, और मैंने 5-10 ~ सेकंड तक स्ट्रेम्स प्राप्त करना समाप्त कर दिया क्योंकि मीडिया लूप के अंदर डेटा प्रोसेस करते समय बफरिंग होती है। यह आपके डेटा पर निर्भर करता है। यदि फ़ंक्शन किसी प्रकार का सरल वॉचडॉग है, तो आपको चेतावनी देता है, उदाहरण के लिए, जब आपकी डिस्क भरी हुई है, तो आपको इसके साथ कोई समस्या नहीं होनी चाहिए। यदि आप एक परमाणु ऊर्जा संयंत्र चेतावनी अलर्ट की जांच कर रहे हैं, तो आप एक शहर के साथ समाप्त हो सकते हैं। पूरी तरह से उड़ा दिया एक्स
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
शेड्यूल मॉड्यूल कुछ समय के बाद चलने वाले शेड्यूलिंग फ़ंक्शंस के लिए है, आप इसे कैसे उपयोग करते हैं एक फ़ंक्शन कॉल को हर बार सेकंड का उपयोग करके time.sleep () का उपयोग किए बिना?
बैशमपायन घोष

2
@Baishampayan: बस एक नया रन शेड्यूल करें।
nosklo

3
उसके बाद पैकेज ओरमथ्थोयर्स ओआरजीपीथ्रोन डॉट ओआरएपकेड्यूलर को इस बिंदु पर एक उल्लेख प्राप्त करना चाहिए।
डैनियल एफ

6
नोट: यह संस्करण बहाव हो सकता है। आप इससे enterabs()बचने के लिए इस्तेमाल कर सकते हैं । यहां तुलना के लिए एक गैर-बहती संस्करण है
jfs

8
@ जावा: क्योंकि "आपका सामान" तात्कालिक नहीं है और 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प्रत्येक कॉल के बाद सेकंड की देरी के साथ फ़ंक्शन निष्पादित करते हैं।
१।

13
यदि आप इसमें कुछ कोड जोड़ते हैं जो कि एक सेकंड से अधिक समय लेता है ... यह समय को बाहर फेंक देगा और पीछे रहना शुरू कर देगा .. इस मामले में स्वीकृत उत्तर सही है ... कोई भी एक साधारण प्रिंट कमांड को लूप कर सकता है और इसने बिना किसी देरी के हर सेकंड दौड़ लगाई ...
गुस्सा 84

5
मैं from time import time, sleepअस्तित्व के निहितार्थ के कारण पसंद करता हूं ;)
होगा

14
काल्पनिक रूप से काम करता है। starttimeयदि आप इसे एक निश्चित समय के लिए समन्वयित करके शुरू करते हैं, तो आपको घटाने की कोई आवश्यकता नहीं है : time.sleep(60 - time.time() % 60)मेरे लिए ठीक काम कर रहा है। मैंने इसका उपयोग किया है time.sleep(1200 - time.time() % 1200)और यह मुझे उस पर लॉग देता है :00 :20 :40, जैसा मैं चाहता था।
टेम्पोर्लवुल्फ

2
कई पुनरावृत्तियों के बाद बहाव से बचने के लिए @AntonSchigur। एक व्यक्तिगत पुनरावृत्ति थोड़ी जल्दी या बाद में शुरू हो सकती है sleep(), timer()सटीकता और लूप बॉडी को निष्पादित करने में कितना समय लगता है, लेकिन औसत पुनरावृत्तियों हमेशा अंतराल सीमाओं पर होती है (भले ही कुछ छूटे हों) while keep_doing_it(): sleep(interval - timer() % interval):। इसकी तुलना while keep_doing_it(): sleep(interval)वहीं करें जहां कई पुनरावृत्तियों के बाद त्रुटियां जमा हो सकती हैं।
20-11 को

71

आप ट्विस्टेड पर विचार करना चाह सकते हैं जो पायथन नेटवर्किंग लाइब्रेरी है जो रिएक्टर पैटर्न को लागू करता है ।

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

जबकि "जबकि सच: नींद (60)" शायद काम करेगा मुड़ शायद पहले से ही कई विशेषताओं को लागू करता है जिनकी आपको अंततः आवश्यकता होगी (डोबेनाइजेशन, लॉगिंग या अपवाद को संभालना जैसा बोबिन द्वारा बताया गया है) और शायद एक अधिक मजबूत समाधान होगा


महान उत्तर के रूप में अच्छी तरह से, बहाव के बिना बहुत सटीक। मुझे आश्चर्य है कि अगर यह कार्य को निष्पादित करने के लिए प्रतीक्षा करते समय सीपीयू को सोता है (उर्फ व्यस्त-प्रतीक्षा नहीं)?
स्मूथवेयर

1
यह मिलीसेकंड स्तर पर बहती है
डेरेक ईडन

"मिलीसेकंड स्तर पर बहती" का क्या अर्थ है?
जीन-पॉल काल्डेरोन

67

यदि आप अपने फ़ंक्शन को समय-समय पर निष्पादित करने के लिए एक गैर-अवरुद्ध तरीका चाहते हैं, तो एक अवरुद्ध अनंत लूप के बजाय मैं थ्रेडेड टाइमर का उपयोग करूंगा। इस तरह से आपका कोड चालू रह सकता है और अन्य कार्य कर सकता है और फिर भी आपके फ़ंक्शन को प्रत्येक n सेकंड कहा जाता है। मैं लंबे, सीपीयू / डिस्क / नेटवर्क गहन कार्यों पर प्रगति की जानकारी को प्रिंट करने के लिए इस तकनीक का उपयोग करता हूं।

यह कोड मैंने एक समान प्रश्न में पोस्ट किया है, स्टार्ट () और स्टॉप () नियंत्रण के साथ:

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!

यह समाधान समय के साथ बहने लगता है; मुझे एक ऐसे संस्करण की आवश्यकता थी जिसका उद्देश्य प्रत्येक एन सेकंड को बहाव के बिना कॉल करना है। मैं एक अलग प्रश्न में एक अद्यतन पोस्ट करूँगा।
युगांक

में def _run(self)मैं चारों ओर तुम क्यों कहते हैं मेरे सिर लपेटो करने कोशिश कर रहा हूँ self.start()से पहले self.function()। क्या आप विस्तार से समझा सकते हैं? मुझे लगता है कि start()पहले कॉल करके self.is_runningहमेशा Falseऐसा होगा, फिर हम हमेशा एक नया धागा तैयार करेंगे।
रिच एपिस्कोपो

1
मुझे लगता है कि मैं इसकी तह तक गया। @ MestreLion का समाधान हर xसेकंड (यानी t = 0, t = 1x, t = 2x, t = 3x, ...) एक फंक्शन चलाता है, जहाँ मूल पोस्टर सैंपल कोड में x सेकंड अंतराल के बीच में एक फंक्शन चलाता है । इसके अलावा, मुझे लगता है कि इस समाधान का एक बग है अगर निष्पादन में intervalलगने वाले समय की तुलना में कम है function। उस स्थिति self._timerमें, startफ़ंक्शन में अधिलेखित हो जाएगा ।
रिच एपिस्कोपो

हां, @RichieEpiscopo, के .function()बाद कॉल .start()t = 0 पर फ़ंक्शन को चलाने के लिए है। और मुझे नहीं लगता कि यह एक समस्या है अगर इससे functionअधिक समय लगता है interval, लेकिन हाँ कोड पर कुछ रेसिंग स्थितियां हो सकती हैं।
MestreLion

यह एकमात्र गैर-अवरुद्ध तरीका है जो मुझे मिल सकता है। धन्यवाद।
backslashN

35

मेरा मानना ​​है कि आसान तरीका:

import time

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

while True:
    executeSomething()

इस तरह से आपके कोड को निष्पादित किया जाता है, फिर यह 60 सेकंड इंतजार करता है फिर इसे फिर से निष्पादित करता है, इंतजार करता है, निष्पादित करता है, आदि ... चीजों को जटिल करने की आवश्यकता नहीं है: डी


यह सच है कि अपरकेस होना चाहिए
सीन कैन

38
वास्तव में यह उत्तर नहीं है: समय नींद () केवल हर निष्पादन के बाद एक्स सेकंड प्रतीक्षा के लिए इस्तेमाल किया जा सकता है। उदाहरण के लिए, यदि आपके फ़ंक्शन को निष्पादित होने में 0.5 सेकंड का समय लगता है और आप समय का उपयोग करते हैं। सो (1), इसका मतलब है कि आपका फ़ंक्शन प्रत्येक 1.5 सेकंड में निष्पादित होता है, न कि 1. आपको वाई मॉड्यूल के लिए कुछ काम करने के लिए अन्य मॉड्यूल और / या थ्रेड्स का उपयोग करना चाहिए। हर X सेकंड में।
कोमराधोमर

1
@kommradHomer: डेव रोव का जवाब दर्शाता है कि आप हर X सेकंड में कुछ चला सकते हैंtime.sleep()
jfs

2
मेरी राय में कोड को लूप time.sleep()में कॉल करना चाहिए while Trueजैसे:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
लियोनार्ड लेपडैतु

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()तुलना में अधिक मजबूत है।
  • कोई बहाव नहीं: मेरा समाधान उस समय का सटीक ट्रैक रखता है जिसे उस समय चलना चाहिए। निष्पादन समय (कई अन्य समाधानों में) के आधार पर कोई बहाव नहीं है।
  • लंघन: मेरा समाधान कार्यों को छोड़ देगा यदि एक निष्पादन में बहुत अधिक समय लगता है (जैसे हर पांच सेकंड में एक्स, लेकिन एक्स को 6 सेकंड लगते हैं)। यह मानक क्रोन व्यवहार है (और अच्छे कारण के लिए)। कई अन्य समाधान तो बस बिना किसी देरी के कई बार कार्य निष्पादित करते हैं। अधिकांश मामलों के लिए (जैसे सफाई कार्य) यह कामना नहीं है। यदि यह है की कामना की, बस का उपयोग next_time += delayकरने के बजाय।

2
बहती नहीं के लिए सबसे अच्छा जवाब।
सेबस्टियन स्टार्क

1
@PirateApp मैं एक अलग धागे में यह करना होगा। आप इसे उसी थ्रेड में कर सकते हैं, लेकिन तब आप अपनी खुद की शेड्यूलिंग प्रणाली की प्रोग्रामिंग करते हैं जो कि एक टिप्पणी के लिए बहुत जटिल है।
एल्फ

1
पायथन में, जीआईएल के लिए धन्यवाद, दो थ्रेड्स में चर तक पहुंच पूरी तरह से सुरक्षित है। और दो थ्रेड्स में पढ़ना कभी भी एक समस्या नहीं होनी चाहिए (अन्य थ्रेडेड वातावरण में भी नहीं)। केवल GIL के बिना सिस्टम में दो अलग-अलग थ्रेड्स से लिखना (जैसे जावा, C ++, आदि में) कुछ स्पष्ट सिंक्रनाइज़ेशन की आवश्यकता है।
एल्फ

1
@ user50473 बिना किसी और जानकारी के मैं पहले थ्रेड की तरफ से काम करना चाहूंगा। एक धागा डेटा को अभी और फिर पढ़ता है और तब तक सोता है जब तक कि इसे करने के लिए फिर से समय न हो। उपरोक्त समाधान का उपयोग इस कोर्स को करने के लिए किया जा सकता है। लेकिन मैं एक अलग तरीके से जाने के कारणों की एक गुच्छा की कल्पना कर सकता था। इतना सौभाग्य :)
Alfe

1
नींद को थ्रेडिंग द्वारा प्रतिस्थापित किया जा सकता है। आवेदन निकलने पर अधिक प्रतिक्रियाशील होने के लिए टाइमआउट के साथ प्रतीक्षा करें। stackoverflow.com/questions/29082268/…
themadmax

20

यहां MestreLion के कोड का अपडेट दिया गया है जो समय के साथ सूखने से बचता है।

यहाँ रिपीटेडटाइमर क्लास ओपी द्वारा अनुरोधित फ़ंक्शन को हर "अंतराल" सेकंड कहता है; शेड्यूल इस बात पर निर्भर नहीं करता है कि फ़ंक्शन को निष्पादित करने में कितना समय लगता है। मुझे यह समाधान पसंद है क्योंकि इसमें बाहरी पुस्तकालय निर्भरता नहीं है; यह सिर्फ शुद्ध अजगर है।

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

उस और क्रोन के बीच मुख्य अंतर यह है कि एक अपवाद अच्छे के लिए डेमन को मार देगा। आप एक अपवाद पकड़ने वाले और लकड़हारे के साथ लपेटना चाह सकते हैं।


4

एक संभावित उत्तर:

import time
t=time.time()

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

1
यह एक बहुत खराब इंतजार में व्यस्त है।
अल्फ

एक गैर अवरुद्ध टाइमर की तलाश में किसी के लिए अच्छा समाधान।
नोएल

3

मैंने शेड्यूल मॉड्यूल का उपयोग करके समाप्त किया । एपीआई अच्छा है।

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 की जांच की है, लेकिन मैं वास्तव में आपूर्ति किए गए वर्कअराउंड को नहीं समझ पाया। क्या किसी को पता है कि मुझे एक काम करने वाला उदाहरण कहां मिल सकता है जो मुख्य धागे को अवरुद्ध नहीं करता है?
5 दिन

1

मैं Tkinter के बाद () विधि का उपयोग करता हूं, जो "गेम को चोरी नहीं करता" ( शेड्यूल मॉड्यूल की तरह जो पहले प्रस्तुत किया गया था), अर्थात यह अन्य चीजों को समानांतर में चलाने की अनुमति देता है:

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 को तेजी से दो बार क्रियान्वित किया जाएगा। यह भी कि मैंने किसी फ़ंक्शन को समाप्त करने के लिए एक साधारण काउंटर का उपयोग एक शर्त के रूप में किया है। आप किसी भी अन्य प्रतियोगिता का उपयोग कर सकते हैं जिसे आप पसंद करते हैं या कोई भी नहीं अगर प्रोग्राम समाप्त होने तक आप क्या कार्य कर सकते हैं (उदाहरण के लिए एक घड़ी)।


अपने शब्दों के साथ सावधान रहें: afterचीजों को समानांतर में चलने की अनुमति नहीं देता है। टिंकर एकल-थ्रेडेड है और एक समय में केवल एक ही काम कर सकता है। यदि कुछ द्वारा निर्धारित किया afterजा रहा है, तो यह बाकी कोड के समानांतर नहीं चल रहा है। यदि दोनों do_something1और do_something2एक ही समय में चलने के लिए निर्धारित हैं, तो वे क्रमिक रूप से चलेंगे, समानांतर में नहीं।
ब्रायन ओकली

सभी अपने समाधान करता है उपयोग करने के लिए है @Apostolos tkinter के बजाय mainloop Sched , mainloop तो यह उसी तरह से वास्तव में काम करता है लेकिन tkinter इंटरफेस जवाब जारी रखने के लिए अनुमति देता है। यदि आप अन्य चीजों के लिए टीक्टर का उपयोग नहीं कर रहे हैं, तो यह शेड्यूल समाधान के संबंध में कुछ भी नहीं बदलता है। आप schedसमाधान में अलग-अलग अंतराल के साथ दो या अधिक अनुसूचित कार्यों का उपयोग कर सकते हैं और यह आपके जैसे ही काम करेगा।
nosklo

नहीं, यह उसी तरह से काम नहीं करता है। मैंने इसे समझाया। एक कार्यक्रम को "लॉक" करता है (अर्थात प्रवाह को रोक देता है, आप कुछ और नहीं कर सकते हैं - जब तक आप सुझाव देते हैं तब तक एक और scecduled काम शुरू भी नहीं करते हैं) जब तक कि यह खत्म नहीं हो जाता है और दूसरा आपके हाथों को मुक्त करता है (यानी आप कर सकते हैं) इसके शुरू होने के बाद अन्य चीजें। आपको इसे खत्म करने के लिए इंतजार नहीं करना होगा। यह एक बड़ा अंतर है। यदि आपने मेरे द्वारा प्रस्तुत विधि की कोशिश की थी, तो आप अपने लिए देख सकते थे। मैंने आपकी कोशिश की है। आप ऐसा क्यों नहीं करते। मेरी भी कोशिश करो?
अपोस्टोलोस

1

यहाँ MestreLion से कोड के लिए एक अनुकूलित संस्करण है। मूल फ़ंक्शन के अतिरिक्त, यह कोड:

1) एक विशिष्ट समय पर टाइमर को आग लगाने के लिए उपयोग किया जाने वाला 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इस परीक्षण के बाद अनिश्चित काल के लिए अनिश्चित काल के लिए कहां रुकना होगा।


नहीं, यह केवल पहले डेटाटाइम को प्रिंट करता है और फिर बंद हो जाता है ...
एलेक्स पोका

क्या आप निश्चित हैं - मैं टर्मिनल में सिर्फ कॉपी और पेस्ट करता हूं। यह तुरंत वापस आ जाता है लेकिन प्रिंटआउट मेरे लिए पृष्ठभूमि में जारी है।
एडम ह्यूजेस

ऐसा लग रहा है कि मुझे यहां कुछ याद आ रहा है। मैंने कोड को test.py में कॉपी / पेस्ट किया है , और python test.py के साथ चलता है । Python2.7 के साथ मुझे डेमॉन को हटाने की आवश्यकता है = यह सच है कि मान्यता प्राप्त नहीं है और मैंने कई प्रिंट पढ़े हैं। Python3.8 के साथ यह पहले प्रिंट के बाद बंद हो जाता है और इसके समाप्त होने के बाद कोई प्रक्रिया सक्रिय नहीं होती है। डेमॉन हटाना = सच है कि मैंने कई प्रिंट पढ़े ...
एलेक्स पोका

हम्म अजीब - मैं ३.१.१० अजगर पर हूँ, लेकिन पता नहीं क्यों यह बात होगी
एडम ह्यूजेस

दोबारा: Python3.4.2 (डेबियन जीएनयू / लिनक्स 8 (जेसी)), डेमन को हटाना पड़ा = यह इतना मल्टीपल-प्रिंट हो सकता है। डेमन के साथ मुझे एक सिंटैक्स त्रुटि मिलती है। Python2.7 और 3.8 के साथ पिछले परीक्षण उबंटू 19.10 पर थे, क्या यह हो सकता है कि डेमन का ओएस के अनुसार अलग तरह से व्यवहार किया जाता है?
एलेक्स पोका

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 टिक होंगे; और उनमें से अधिकांश सही ऑफसेट पर आपके द्वारा पसंद किए जाने वाले मिनट में घटित होंगे।

जब तक सुधार की आवश्यकता नहीं होती है, तब तक मेरे सिस्टम पर मुझे एक सेकंड का </ 20 वां बहाव मिलता है।

इस पद्धति का लाभ घड़ी के बहाव का संकल्प है; यदि आप प्रति टिक के एक आइटम को जोड़ने जैसी चीजें कर रहे हैं, तो आपको समस्या हो सकती है और आपको प्रति घंटे 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()

उपयोगकर्ता इनपुट के आधार पर यह समय के हर अंतराल पर उस पद्धति को पुनरावृत्त करेगा।
रविगुप्त

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()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.