প্রতি x সেকেন্ডে কোনও ক্রিয়াকলাপ বারবার কার্যকর করার সর্বোত্তম উপায় কী?


282

আমি বার বার পাইথনে একটি ক্রিয়াকলাপটি প্রতি 60 সেকেন্ডে চিরতরে চালিত করতে চাই (ঠিক যেমন এনজাইটিম সি তে NSTimer )। এই কোডটি ডেমন হিসাবে চলবে এবং কার্যকরভাবে প্রতি মিনিটে ক্রোন ব্যবহার করে পাইথন স্ক্রিপ্ট কল করার মতো, তবে এটি ব্যবহারকারীর দ্বারা সেট আপ করা প্রয়োজন ছাড়াই।

ইন একটি ক্রন পাইথন বাস্তবায়িত সম্বন্ধে প্রশ্নগুলির , সমাধান কার্যকরভাবে শুধু মনে হচ্ছে, ঘুম () এক্স সেকেন্ডের জন্য। আমার এত উন্নত কার্যকারিতা দরকার নেই তাই সম্ভবত এর মতো কিছু কাজ করবে

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

এই কোডটি নিয়ে কোনও পূর্ববর্তী সমস্যা আছে?


83
একটি পেডেন্টিক পয়েন্ট, তবে সমালোচনামূলক হতে পারে, আপনার কোডের উপরের কোডটি 60০ সেকেন্ডে কার্যকর হয় না এটি মৃত্যুদণ্ড কার্যকর করার মধ্যে একটি second০ সেকেন্ডের ব্যবধান রাখে। এটি শুধুমাত্র প্রতি 60 সেকেন্ডে ঘটে যদি আপনার সম্পাদিত কোডটি কোনও সময় না নেয়।
সাইমন

4
time.sleep(60)
jfs

5
আমি এখনও ভাবছি: এই কোডটি নিয়ে কি কোনও পূর্ববর্তী সমস্যা আছে?
কলা

1
"দূরবর্তী সমস্যা" হ'ল আপনি কেবল সময়.স্লিপ (60) ব্যবহার করে প্রতি ঘন্টা 60 টি পুনরাবৃত্তি আশা করতে পারবেন না। সুতরাং আপনি যদি পুনরাবৃত্তি প্রতি একটি আইটেম সংযোজন এবং সেট দৈর্ঘ্যের একটি তালিকা রাখেন ... সেই তালিকার গড় সময়ের একটি সামঞ্জস্যপূর্ণ "সময়" উপস্থাপন করবে না; সুতরাং "মুভিং এভারেজ" এর মতো ফাংশনগুলি ডেটা পয়েন্টগুলি উল্লেখ করা যেতে পারে যা খুব পুরানো, যা আপনার ইঙ্গিতকে বিকৃত করবে।
লিটারপ্রেসেন্স

2
@ বনানা হ্যাঁ, আপনি যে কোনও সমস্যার কারণেই আশা করতে পারেন কারণ আপনার স্ক্রিপ্টটি প্রতি 60 সেকেন্ডে একেবারে কার্যকর হয় না। এই ক্ষেত্রে. আমি ভিডিও স্ট্রিমগুলি বিভক্ত করতে এবং আপলোড'এর জন্য এরকম কিছু করতে শুরু করেছিলাম এবং আমি 5-10 ~ সেকেন্ড দীর্ঘ স্ট্রিমগুলি পেয়েছি কারণ আমি লুপের অভ্যন্তরে ডেটা প্রক্রিয়াকরণের সময় মিডিয়া কাতারে বাফার করছি। এটি আপনার ডেটা উপর নির্ভর করে। যদি ফাংশনটি কোনও ধরণের সরল ওয়াচডগ আপনাকে সতর্ক করে দেয়, উদাহরণস্বরূপ, যখন আপনার ডিস্কটি পূর্ণ থাকে তবে আপনার এটিকে নিয়ে কোনও সমস্যা করা উচিত নয় you're আপনি যদি একটি পারমাণবিক বিদ্যুৎ কেন্দ্রের সতর্কতা সতর্কতাগুলি পরীক্ষা করে থাকেন তবে কোনও শহর শেষ হতে পারে সম্পূর্ণরূপে
ফুটিয়ে

উত্তর:


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
সময়সূচী মডিউলটি কিছু সময়ের পরে চলার জন্য নির্ধারিত ফাংশনগুলির জন্য, আপনি কীভাবে সময় ব্যবহার না করে প্রতি x সেকেন্ডে কোনও ফাংশন কলটির পুনরাবৃত্তি করতে পারেন? ঘুম ()?
বৈশাম্পায়ান ঘোষ

2
@ বৈশাম্পায়ান: একটি নতুন রান নির্ধারণ করুন।
nosklo

3
তারপর এ apscheduler packages.python.org/APScheduler এছাড়াও এই সময়ে একটি উল্লেখ পাওয়া উচিত।
ড্যানিয়েল এফ

6
দ্রষ্টব্য: এই সংস্করণটি প্রবাহিত হতে পারে। আপনি enterabs()এটি এড়াতে ব্যবহার করতে পারেন । তুলনার জন্য এখানে একটি নন-প্রবাহিত সংস্করণ
jfs

8
@ জাভাসা: কারণ "আপনার জিনিসগুলি করুন" তাত্ক্ষণিক নয় এবং এর থেকে ত্রুটিগুলি time.sleepএখানে জমা হতে পারে। "প্রতি এক্স সেকেন্ডে এক্সিকিউট করুন" এবং "বার বার এক্স এক্স সেকেন্ডের বিলম্বের সাথে এক্সিকিউট করুন" এক নয়। আরও দেখুন এই মন্তব্যটি
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
আপনি যদি এখানে কোনও কোড যুক্ত করেন যা এক সেকেন্ডের চেয়ে বেশি সময় নিয়েছে ... এটি সময় নিক্ষেপ করবে এবং পিছিয়ে যেতে শুরু করবে .. এই ক্ষেত্রে গৃহীত উত্তরটি সঠিক ... যে কোনও সাধারণ মুদ্রণ কমান্ড লুপ করতে পারে এবং এটি দেরি না করে প্রতি সেকেন্ডে
ক্ষুব্ধ 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
একাধিক পুনরাবৃত্তির পরে চালিকা এড়াতে @ অ্যান্টসচিগার একজন স্বতন্ত্র পুনরাবৃত্তির সামান্য কখনো কখনো তার উপর নির্ভর করে শুরু হতে পারে sleep(), timer()স্পষ্টতা এবং কতদিন এটা লুপ শরীরের চালানো কিন্তু গড় পুনরাবৃত্তিও সর্বদা (এমনকি যদি কিছু এড়ানো হয়েছে হয়) ব্যবধান গণ্ডি উপর ঘটতে সময় লাগে: while keep_doing_it(): sleep(interval - timer() % interval)। এটির সাথে তুলনা করুন while keep_doing_it(): sleep(interval)যেখানে বেশ কয়েকটি পুনরাবৃত্তির পরে ত্রুটিগুলি জমা হতে পারে।
jfs

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

যদিও "সত্য: ঘুম ()০)" সম্ভবত কাজ করবে টুইস্টটি সম্ভবত ইতিমধ্যে আপনার প্রয়োজনীয় বৈশিষ্ট্যগুলির অনেকগুলি প্রয়োগ করে (ডেমোনাইজেশন, লগিং বা ব্যোবিন্স দ্বারা চিহ্নিত হিসাবে ব্যতিক্রম হ্যান্ডলিং) এবং সম্ভবত এটি আরও দৃust় সমাধান হতে পারে


দুর্দান্ত উত্তরও বামন ছাড়াই খুব নির্ভুল। আমি ভাবছি যদি এটি সিপিইউটিকে পাশাপাশি ঘুমানোর জন্য বসায় তবে টাস্কটি কার্যকর করার অপেক্ষায় (ওরফে ব্যস্ত-অপেক্ষায় নেই)?
স্মুথওয়্যার

1
মিলিসেকেন্ড পর্যায়ে এই ড্রিফ্টস
ডেরেক ইডেন

"মিলিসেকেন্ড স্তরে ড্রিফ্ট" বলতে কী বোঝায়?
জিন-পল ক্যালডারোন

67

আপনি যদি নিজের ফাংশনটি পর্যায়ক্রমে সম্পাদন করার জন্য অ-অবরুদ্ধ উপায় চান তবে ব্লকিং অসীম লুপের পরিবর্তে আমি একটি থ্রেডযুক্ত টাইমার ব্যবহার করব। এইভাবে আপনার কোডটি চলতে থাকবে এবং অন্যান্য কাজগুলি চালিয়ে যেতে পারে এবং প্রতি এন সেকেন্ডে আপনার ফাংশনটি কল করতে পারে। দীর্ঘ, সিপিইউ / ডিস্ক / নেটওয়ার্ক নিবিড় কাজগুলিতে অগ্রগতির তথ্য মুদ্রণের জন্য আমি এই কৌশলটি প্রচুর ব্যবহার করি।

শুরু () এবং স্টপ () নিয়ন্ত্রণের সাথে আমি একটি অনুরূপ প্রশ্নে পোস্ট করা কোডটি এখানে:

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
আমি মনে করি এটির নীচে পৌঁছেছি। @ ম্যাস্ট্রিলিয়নের সমাধান প্রতি xসেকেন্ডে একটি ফাংশন চালায় (অর্থাত্ t = 0, t = 1x, t = 2x, t = 3x, ...) যেখানে মূল পোস্টারগুলিতে নমুনা কোডটি x সেকেন্ডের বিরতিতে একটি ফাংশন চালায় । এছাড়াও, আমি বিশ্বাস করি যে এই সমাধানটি কার্যকর করতে intervalযে সময় লাগে তার চেয়ে কম হলে একটি বাগ থাকে function। সেক্ষেত্রে, self._timerমুছে ফেলা পাবেন startফাংশন।
ধনী এপিস্কোপো

হ্যাঁ, @ রিচিএপিস্কোপো, তার .function()পরে কলটি .start()হল টি = 0 এ ফাংশনটি চালানো। এবং আমি মনে করি না যে এটির functionচেয়ে বেশি সময় নিলে সমস্যা হবে intervalতবে হ্যাঁ কোডে রেসিংয়ের কিছু শর্ত থাকতে পারে।
MestreLion

এটি আমিই পেতে পারি না- ধন্যবাদ।
ব্যাকস্ল্যাশএন

35

আমার বিশ্বাস করা সহজ উপায়:

import time

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

while True:
    executeSomething()

এইভাবে আপনার কোডটি কার্যকর করা হয়, তারপরে এটি 60 সেকেন্ড অপেক্ষা করে তারপরে এটি আবার কার্যকর হয়, অপেক্ষা করে, কার্যকর করা ইত্যাদি ... জিনিসগুলিকে জটিল করার দরকার নেই: ডি


সত্যটির কীওয়ার্ডটি বড় হাতের হওয়া উচিত
সান কেইন

38
প্রকৃতপক্ষে এটির উত্তর নয়: সময় ঘুম () কেবলমাত্র প্রতিটি সম্পাদনের পরে এক্স সেকেন্ডের জন্য অপেক্ষা করা যেতে পারে। উদাহরণস্বরূপ, যদি আপনার ফাংশনটি সম্পাদন করতে 0.5 সেকেন্ড সময় নেয় এবং আপনি সময় ব্যবহার করেন s প্রতি এক্স সেকেন্ডে
kommradHomer

1
@ কমারডহোমর: ডেভ রোভের উত্তর প্রমাণ করে যে আপনি প্রতি 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() করা তুলনায় তুলনামূলকভাবে অনেক বেশি দৃust়।
  • কোন প্রবাহ: আমার যে সময়টি চালানো হবে তার সঠিক ট্র্যাক রাখে। মৃত্যুদন্ড কার্যকর হওয়ার সময় (অন্যান্য অনেকগুলি সমাধানের মতো) উপর নির্ভর করে কোনও প্রবাহ নেই।
  • এড়িয়ে যাওয়া : আমার সমাধান কার্য সম্পাদন করবে যদি কোনও মৃত্যুদণ্ড কার্যকর করতে খুব বেশি সময় লাগে (যেমন, প্রতি পাঁচ সেকেন্ডে এক্স করুন, তবে এক্সটি seconds সেকেন্ড সময় নিয়েছিল)। এটি স্ট্যান্ডার্ড ক্রোন আচরণ (এবং একটি ভাল কারণে)। অন্য অনেকগুলি সমাধানের পরে কোনও দেরি না করে কেবল একাধিকবার টাস্কটি কার্যকর করা হয়। বেশিরভাগ ক্ষেত্রে (যেমন ক্লিনআপের কাজগুলি) এটি কাম্য নয়। যদি হয় আকাঙ্ক্ষিত, সহজভাবে ব্যবহার next_time += delayপরিবর্তে।

2
না প্রবাহিত জন্য সেরা উত্তর।
সেবাস্তিয়ান স্টার্ক

1
@ পাইরেট অ্যাপ আমি এটি অন্য থ্রেডে করব। আপনি এটি একই থ্রেডে করতে পারেন তবে তারপরে আপনি আপনার নিজের সময়সূচী সিস্টেমটি প্রোগ্রামিং শেষ করবেন যা কোনও মন্তব্যের পক্ষে খুব জটিল।
Alfe

1
পাইথনে, জিআইএলকে ধন্যবাদ, দুটি থ্রেডে ভেরিয়েবল অ্যাক্সেস করা পুরোপুরি নিরাপদ। এবং কেবল দুটি থ্রেডে পড়া কখনই সমস্যা হওয়া উচিত নয় (অন্যান্য থ্রেডযুক্ত পরিবেশেও নয়)। জিআইএল ব্যতীত একটি সিস্টেমে কেবল দুটি পৃথক থ্রেড থেকে লেখার জন্য (যেমন জাভা, সি ++ ইত্যাদি)) কিছু স্পষ্ট সুসংগত প্রয়োজন।
আলফ

1
@ ব্যবহারকারী 50473 কোনও তথ্য ছাড়াই আমি প্রথমে থ্রেডযুক্ত দিক থেকে টাস্কটির কাছে যাব। একটি থ্রেড এখন এবং তারপর ডেটা পড়ে এবং তারপরে আবার এটি করার সময় না হওয়া পর্যন্ত ঘুমায় s উপরের সমাধানটি অবশ্যই এটি করতে ব্যবহৃত হতে পারে। তবে আমি ভিন্ন উপায়ে যাওয়ার অনেকগুলি কারণ কল্পনা করতে পারি। শুভকামনা :)
Alfe

1
ঘুম থ্রেডিংয়ের মাধ্যমে প্রতিস্থাপন করা যেতে পারে application 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 চেক করেছি, তবে আমি সরবরাহিত কর্মক্ষেত্রটি বুঝতে পারি নি। কেউ কি জানেন যেখানে আমি এমন একটি কর্মের উদাহরণ খুঁজে পেতে পারি যা মূল থ্রেডটি ব্লক করে না?
ডেড্রিম

1

আমি টিন্টার () পদ্ধতির পরে ব্যবহার করি যা "গেমটি চুরি করে না" ( আগে উপস্থাপিত শিডিয়ুল মডিউলটির মতো ), অর্থাৎ এটি অন্যান্য জিনিসকে সমান্তরালে চালানোর অনুমতি দেয়:

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()সমান্তরাল এবং যে কোনও বিরতি গতিতে চলতে পারে। এখানে, ২ য় জনকে দ্রুত দ্বিগুণ কার্যকর করা হবে N এছাড়াও উল্লেখ্য যে আমি কোনও ফাংশন বন্ধ করতে শর্ত হিসাবে একটি সাধারণ কাউন্টার ব্যবহার করেছি। আপনি প্রোগ্রামটি শেষ না হওয়া অবধি কোন ফাংশনটি চালাতে চান তবে আপনি যেমন পছন্দ করেন না এমন কিছুই বা কোনওটিই ব্যবহার করতে পারেন না (যেমন একটি ঘড়ি)।


আপনার কথার সাথে সাবধান থাকুন: afterজিনিসগুলিকে সমান্তরালে চলতে দেয় না run টিন্টিটার একক থ্রেডযুক্ত এবং একসাথে কেবল একটি কাজ করতে পারে। যদি নির্ধারিত কিছু afterচলমান থাকে, তবে এটি বাকী কোডের সাথে সমান্তরালে চলমান নয়। উভয় তাহলে do_something1এবং do_something2একই সময়ে চালানোর জন্য নির্ধারণ করা হয়, তখন তারা ক্রমানুসারে চালানো হবে সমান্তরাল না।
ব্রায়ান ওকলে

সব আপনার সমাধান করে ব্যবহার করা @Apostolos tkinter পরিবর্তে mainloop sched , mainloop তাই এটি একই ভাবে ঠিক কাজ করে কিন্তু tkinter ইন্টারফেসগুলি সাড়া অবিরত করতে পারবেন। আপনি যদি অন্য জিনিসের জন্য টিন্টার ব্যবহার না করেন তবে সময়সূচী সমাধানের ক্ষেত্রে এটি কোনও পরিবর্তন করে না। আপনি schedসমাধানটিতে বিভিন্ন অন্তর সহ দুটি বা ততোধিক নির্ধারিত ফাংশন ব্যবহার করতে পারেন এবং এটি ঠিক আপনার মতোই কাজ করবে।
nosklo

না, এটি একইভাবে কাজ করে না। আমি এটি ব্যাখ্যা। প্রোগ্রামটি "তালাবিদ্ধ" করে (যেমন প্রবাহ বন্ধ করে দেয়, আপনি আর কিছু করতে পারবেন না - এমনকি আপনার পরামর্শ অনুযায়ী অন্য মনোরম কাজ শুরুও করবেন না) যতক্ষণ না এটি শেষ হয় এবং অপরটি আপনার হাতে / বিনামূল্যে মুক্ত না করে (যেমন আপনি করতে পারেন) এটি শুরু হওয়ার পরে অন্য জিনিসগুলি Youআপনি এটি শেষ হওয়ার অপেক্ষা করতে হবে না This এটি একটি বিশাল পার্থক্য I আপনি যে পদ্ধতিটি উপস্থাপন করেছেন তা যদি আপনি ব্যবহার করে থাকেন তবে আপনি নিজেই দেখতে পেতেন I আমি আপনার চেষ্টা করেছি you আপনি কেন না আমারও চেষ্টা করে দেখুন?
অ্যাপোস্টোলোস

1

এখানে MestreLion থেকে কোডটিতে একটি রূপান্তরিত সংস্করণ। মূল ফাংশন ছাড়াও, এই কোড:

1) একটি নির্দিষ্ট সময়ে টাইমার ফায়ার করতে ব্যবহৃত ফার্স্ট_ইন্টারওয়াল যুক্ত করুন (কলারকে প্রথম_আন্টারওয়াল গণনা করতে হবে এবং পাস করতে হবে)

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এই থ্যাডটি বন্ধ হওয়ার অপেক্ষায় পরীক্ষা চালানোর পরে অনির্দিষ্টকালের জন্য স্থির হয়ে থাকতে পারে এমন সমস্যা ছিল ।


না, এটি কেবল প্রথম তারিখের সময়টি প্রিন্ট করে এবং তারপরে বন্ধ হয়ে যায় ...
অ্যালেক্স পোকা

আপনি কি নিশ্চিত - আমি টার্মিনালে কেবল অনুলিপি করে আটকালাম। এটি এখনই ফিরে আসে তবে মুদ্রণটি আমার জন্য পটভূমিতে অবিরত থাকে।
অ্যাডাম হিউজেস

দেখে মনে হচ্ছে আমি এখানে কিছু মিস করছি। আমি কোডটি টেস্ট.পিতে কপি / পেস্ট করেছি এবং পাইথন টেস্ট.পি দিয়ে চালাচ্ছি । পাইথন 2.7 দিয়ে আমার ডেমন = অপসারণ করা দরকার এটি সত্য যা স্বীকৃত নয় এবং আমি একাধিক প্রিন্ট পড়েছি। পাইথন ৩.৮ দিয়ে এটি প্রথম মুদ্রণের পরে বন্ধ হয়ে যায় এবং শেষ হওয়ার পরে কোনও প্রক্রিয়া সক্রিয় হয় না। ডেমন সরানো = সত্য আমি একাধিক প্রিন্ট পড়েছি ...
অ্যালেক্স পোকা

হুম অদ্ভুত - আমি পাইথনটিতে 3....১০ কিন্তু জানি না কেন বিষয়টি গুরুত্ব পাবে
অ্যাডাম হিউজ

আবার: পাইথন ৩.৪.২ (ডেবিয়ান জিএনইউ / লিনাক্স ৮ (জেসি)), ডেমন = সত্য মুছে ফেলতে হয়েছিল যাতে এটি একাধিক-মুদ্রণ করতে পারে। সঙ্গে ডেমন আমি একটি বাক্য গঠন ত্রুটি পেতে। পাইথন 2.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 টি টিক্স থাকবে; এবং সেগুলির বেশিরভাগটি আপনার পছন্দ অনুযায়ী যে মুহুর্তে অফসেটে ঘটবে।

আমার সিস্টেমে আমি সংশোধনের প্রয়োজন না হওয়া পর্যন্ত এক সেকেন্ডের <1/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

কোনও অতিরিক্ত liণপত্র ব্যবহার না করেই এখানে আরও একটি সমাধান।

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.