পাইথন থ্রেডিং.টিমার - প্রতি 'এন' সেকেন্ডে ফাংশনটি পুনরাবৃত্তি করুন


96

আমি প্রতি 0.5 সেকেন্ডে একটি ফাংশন বন্ধ করতে চাই এবং টাইমারটি শুরু করতে এবং থামাতে এবং রিসেট করতে সক্ষম হতে চাই। পাইথন থ্রেড কীভাবে কাজ করে সে সম্পর্কে আমি খুব বেশি জ্ঞাত নই এবং পাইথন টাইমার নিয়ে সমস্যা হয়।

যাইহোক, আমি দু'বার RuntimeError: threads can only be started onceকার্যকর করার সময় আমি পেতে থাকি threading.timer.start()। এটির জন্য কি কোনও কাজ আছে? আমি threading.timer.cancel()প্রতিটি শুরুর আগে আবেদন করার চেষ্টা করেছি ।

সুডোকোড:

t=threading.timer(0.5,function)
while True:
    t.cancel()
    t.start()

উত্তর:


114

সেরা উপায় হ'ল একবার টাইমার থ্রেড শুরু করা। আপনার টাইমার থ্রেডের অভ্যন্তরে আপনি নিম্নলিখিত কোডগুলি দিতেন

class MyThread(Thread):
    def __init__(self, event):
        Thread.__init__(self)
        self.stopped = event

    def run(self):
        while not self.stopped.wait(0.5):
            print("my thread")
            # call a function

টাইমার শুরু হওয়া কোডটিতে আপনি টাইমারটি setথামানোর জন্য থামানো ইভেন্টটি করতে পারেন ।

stopFlag = Event()
thread = MyThread(stopFlag)
thread.start()
# this will stop the timer
stopFlag.set()

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

13
ঠিক আছে, আপনি যদি টাইমার থ্রেডটি তত্ক্ষণাত বন্ধ করতে সক্ষম হতে চান তবে কেবল একটি threading.Eventএবং এর waitপরিবর্তে ব্যবহার করুন sleep। তারপরে, এটি জাগ্রত করতে, কেবল ইভেন্টটি সেট করুন। আপনার তখনও দরকার নেই self.stoppedকারণ আপনি কেবল ইভেন্টের পতাকাটি পরীক্ষা করেন।
nneonneo

4
ইভেন্টটি টাইমার থ্রেডকে বাধা দেওয়ার জন্য কঠোরভাবে ব্যবহৃত হবে। সাধারণত, সময়টি event.waitশেষ হয়ে যায় এবং ঘুমের মতো কাজ করে, তবে আপনি যদি থ্রেডটি থামাতে (বা অন্যথায় থ্রেডকে বাধা দিতে) চান তবে আপনি থ্রেডের ইভেন্টটি সেট করে রেখেছিলেন এবং তা অবিলম্বে ঘুম থেকে উঠবে।
nneonneo

4
আমি ইভেন্ট.ওয়েট () ব্যবহার করার জন্য আমার উত্তর আপডেট করেছি। পরামর্শের জন্য ধন্যবাদ।
হান্স তারপরে

4
শুধু একটি প্রশ্ন, আমি তার পরে থ্রেডটি পুনরায় চালু করতে পারি কীভাবে? কলিং thread.start()আমাকে দেয়threads can only be started once
মোটাশেম এমকে

33

পাইথনে সেটআইন্টারওয়ালের সমতুল্য থেকে :

import threading

def setInterval(interval):
    def decorator(function):
        def wrapper(*args, **kwargs):
            stopped = threading.Event()

            def loop(): # executed in another thread
                while not stopped.wait(interval): # until stopped
                    function(*args, **kwargs)

            t = threading.Thread(target=loop)
            t.daemon = True # stop if the program exits
            t.start()
            return stopped
        return wrapper
    return decorator

ব্যবহার:

@setInterval(.5)
def function():
    "..."

stop = function() # start timer, the first call is in .5 seconds
stop.set() # stop the loop
stop = function() # start new timer
# ...
stop.set() 

বা এখানে একই কার্যকারিতা কিন্তু ডেকরেটারের পরিবর্তে স্বতন্ত্র ফাংশন হিসাবে :

cancel_future_calls = call_repeatedly(60, print, "Hello, World")
# ...
cancel_future_calls() 

থ্রেড ব্যবহার না করে এটি কীভাবে করা যায় তা এখানে


আপনি কীভাবে ডেকোরেটর ব্যবহার করার সময় অন্তর পরিবর্তন করবেন? বলুন আমি রানটাইমের সময় .5 এস পরিবর্তন করতে চাই 1 সেকেন্ডে বা যাই হোক না কেন?
লাইটএক্সএক্স

@ লাইটএক্সএক্সএক্স: শুধু ব্যবহার করুন @setInterval(1)
jfs

এইচএম সুতরাং হয় আমি কিছুটা মন্থর বা আপনি আমাকে ভুল বুঝেছিলেন। আমি রানটাইম বলতে চাইছিলাম আমি জানি যে আমি যে কোনও সময় উত্স কোডে ডেকরেটারটি পরিবর্তন করতে পারি। কী, উদাহরণস্বরূপ, আমার তিনটি ফাংশন ছিল, প্রত্যেকটি @setInterval (n) দিয়ে সজ্জিত। এখন রানটাইমে আমি ফাংশন 2 এর ব্যবধান পরিবর্তন করতে চাই তবে 1 এবং 3 ফাংশনটি একা রেখে চলেছি।
লাইটএক্স

@ লাইটএক্সএক্স: আপনি বিভিন্ন ইন্টারফেস ব্যবহার করতে পারেন যেমন stop = repeat(every=second, call=your_function); ...; stop(),।
jfs

4
@ লাইটএক্সএক্সএক্স: এখানে একটি অ- stop = call_repeatedly(interval, your_function); ...; stop()
সজ্জনকারী

31

টাইমার থ্রেড ব্যবহার করে-

from threading import Timer,Thread,Event


class perpetualTimer():

   def __init__(self,t,hFunction):
      self.t=t
      self.hFunction = hFunction
      self.thread = Timer(self.t,self.handle_function)

   def handle_function(self):
      self.hFunction()
      self.thread = Timer(self.t,self.handle_function)
      self.thread.start()

   def start(self):
      self.thread.start()

   def cancel(self):
      self.thread.cancel()

def printer():
    print 'ipsem lorem'

t = perpetualTimer(5,printer)
t.start()

এটি দ্বারা বন্ধ করা যেতে পারে t.cancel()


4
আমি বিশ্বাস করি যে cancelপদ্ধতিটিতে একটি কোড রয়েছে a যখন এটি বলা হয়, থ্রেড হয় 1) চলমান বা 2) চলমান নয়। 1) আমরা ফাংশনটি চালানোর জন্য অপেক্ষা করছি, সুতরাং বাতিল করা ভাল কাজ করবে। 2) আমরা বর্তমানে চলছি, সুতরাং বাতিলকরণের বর্তমান কার্যকরকরণে কোনও প্রভাব পড়বে না। তদ্ব্যতীত, বর্তমান সম্পাদনটি নিজেই পুনঃনির্ধারিত করে তাই এটি ভবিষ্যতের এতিয়ারে প্রভাব ফেলবে না।
ধনী এপিস্কোপো

4
এই কোডটি প্রতিবার টাইমার ডাউন হয়ে গেলে একটি নতুন থ্রেড তৈরি করে। গৃহীত উত্তরের তুলনায় এটি একটি বিশাল বর্জ্য।
অ্যাড্রিয়ান W

এই সমাধানটি এড়ানো উচিত, উপরে উল্লিখিত কারণে: এটি প্রতিবার একটি নতুন থ্রেড তৈরি করে
পিঞ্চিয়া

19

হ্যানস তারপরের উত্তরে কিছুটা উন্নতি করা , আমরা কেবল টাইমার ফাংশনটি সাবক্লাস করতে পারি। নিম্নলিখিতটি আমাদের পুরো "পুনরাবৃত্ত টাইমার" কোডে পরিণত হয় এবং এটি থ্রেডিংয়ের জন্য ড্রপ-ইন প্রতিস্থাপন হিসাবে ব্যবহার করা যেতে পারে all একই একই যুক্তি সহ টাইমার:

from threading import Timer

class RepeatTimer(Timer):
    def run(self):
        while not self.finished.wait(self.interval):
            self.function(*self.args, **self.kwargs)

ব্যবহারের উদাহরণ:

def dummyfn(msg="foo"):
    print(msg)

timer = RepeatTimer(1, dummyfn)
timer.start()
time.sleep(5)
timer.cancel()

নিম্নলিখিত আউটপুট উত্পাদন করে:

foo
foo
foo
foo

এবং

timer = RepeatTimer(1, dummyfn, args=("bar",))
timer.start()
time.sleep(5)
timer.cancel()

উত্পাদন

bar
bar
bar
bar

এই পদ্ধতিটি আমাকে টাইমার থ্রেড শুরু / বাতিল / শুরু / বাতিল করার অনুমতি দেবে?
পল নফফ

4
না। যদিও এই পদ্ধতির সাহায্যে আপনি একটি সাধারণ টাইমার দিয়ে যা কিছু করতে চান, আপনি সাধারণ টাইমার দিয়ে এটি করতে পারবেন না। যেহেতু শুরু / বাতিল অন্তর্নিহিত থ্রেডের সাথে সম্পর্কিত, আপনি যদি একটি থ্রেড .start () পূর্বে .cancel () 'এড করার চেষ্টা করেন তবে আপনি একটি ব্যতিক্রম পাবেন RuntimeError: threads can only be started once,।
ডান

4
সত্যিই মার্জিত সমাধান! অদ্ভুত যে তারা কেবল এমন কোনও শ্রেণি অন্তর্ভুক্ত করেনি যা এটি করে।
রজার ডাল

এই সমাধানটি খুব চিত্তাকর্ষক, তবে কীভাবে পাইথন 3 থ্রেডিং টাইমার ইন্টারফেস ডকুমেন্টেশন পড়ার মাধ্যমে এটি কীভাবে তৈরি করা হয়েছিল তা বোঝার জন্য আমি সংগ্রাম করেছি । উত্তরটি threading.pyমডিউলে গিয়েই প্রয়োগটি জানার উপর নির্ভর করে।
আদম.এট.এপসিলন

15

ওপি যেমন অনুরোধ করেছে তেমন টাইমার ব্যবহার করে সঠিক উত্তর দেওয়ার স্বার্থে আমি স্বপ্নিল জারিওয়ালের উত্তরটি উন্নত করব :

from threading import Timer


class InfiniteTimer():
    """A Timer class that does not stop, unless you want it to."""

    def __init__(self, seconds, target):
        self._should_continue = False
        self.is_running = False
        self.seconds = seconds
        self.target = target
        self.thread = None

    def _handle_target(self):
        self.is_running = True
        self.target()
        self.is_running = False
        self._start_timer()

    def _start_timer(self):
        if self._should_continue: # Code could have been running when cancel was called.
            self.thread = Timer(self.seconds, self._handle_target)
            self.thread.start()

    def start(self):
        if not self._should_continue and not self.is_running:
            self._should_continue = True
            self._start_timer()
        else:
            print("Timer already started or running, please wait if you're restarting.")

    def cancel(self):
        if self.thread is not None:
            self._should_continue = False # Just in case thread is running and cancel fails.
            self.thread.cancel()
        else:
            print("Timer never started or failed to initialize.")


def tick():
    print('ipsem lorem')

# Example Usage
t = InfiniteTimer(0.5, tick)
t.start()

3

আমি কিছু কনসোল ঘড়ি তৈরির জন্য স্বপনি-জারিওয়ালা কোডে কিছু কোড পরিবর্তন করেছি।

from threading import Timer, Thread, Event
from datetime import datetime

class PT():

    def __init__(self, t, hFunction):
        self.t = t
        self.hFunction = hFunction
        self.thread = Timer(self.t, self.handle_function)

    def handle_function(self):
        self.hFunction()
        self.thread = Timer(self.t, self.handle_function)
        self.thread.start()

    def start(self):
        self.thread.start()

def printer():
    tempo = datetime.today()
    h,m,s = tempo.hour, tempo.minute, tempo.second
    print(f"{h}:{m}:{s}")


t = PT(1, printer)
t.start()

আউটপুট

>>> 11:39:11
11:39:12
11:39:13
11:39:14
11:39:15
11:39:16
...

টিন্টার গ্রাফিক ইন্টারফেস সহ টাইমার

এই কোডটি ক্লিনিক টাইমারটিকে টিন্টার দিয়ে একটি সামান্য উইন্ডোয় রাখে

from threading import Timer, Thread, Event
from datetime import datetime
import tkinter as tk

app = tk.Tk()
lab = tk.Label(app, text="Timer will start in a sec")
lab.pack()


class perpetualTimer():

    def __init__(self, t, hFunction):
        self.t = t
        self.hFunction = hFunction
        self.thread = Timer(self.t, self.handle_function)

    def handle_function(self):
        self.hFunction()
        self.thread = Timer(self.t, self.handle_function)
        self.thread.start()

    def start(self):
        self.thread.start()

    def cancel(self):
        self.thread.cancel()


def printer():
    tempo = datetime.today()
    clock = "{}:{}:{}".format(tempo.hour, tempo.minute, tempo.second)
    try:
        lab['text'] = clock
    except RuntimeError:
        exit()


t = perpetualTimer(1, printer)
t.start()
app.mainloop()

ফ্ল্যাশকার্ডস গেমের একটি উদাহরণ (সাজানো)

from threading import Timer, Thread, Event
from datetime import datetime


class perpetualTimer():

    def __init__(self, t, hFunction):
        self.t = t
        self.hFunction = hFunction
        self.thread = Timer(self.t, self.handle_function)

    def handle_function(self):
        self.hFunction()
        self.thread = Timer(self.t, self.handle_function)
        self.thread.start()

    def start(self):
        self.thread.start()

    def cancel(self):
        self.thread.cancel()


x = datetime.today()
start = x.second


def printer():
    global questions, counter, start
    x = datetime.today()
    tempo = x.second
    if tempo - 3 > start:
        show_ans()
    #print("\n{}:{}:{}".format(tempo.hour, tempo.minute, tempo.second), end="")
    print()
    print("-" + questions[counter])
    counter += 1
    if counter == len(answers):
        counter = 0


def show_ans():
    global answers, c2
    print("It is {}".format(answers[c2]))
    c2 += 1
    if c2 == len(answers):
        c2 = 0


questions = ["What is the capital of Italy?",
             "What is the capital of France?",
             "What is the capital of England?",
             "What is the capital of Spain?"]

answers = "Rome", "Paris", "London", "Madrid"

counter = 0
c2 = 0
print("Get ready to answer")
t = perpetualTimer(3, printer)
t.start()

আউটপুট:

Get ready to answer
>>> 
-What is the capital of Italy?
It is Rome

-What is the capital of France?
It is Paris

-What is the capital of England?
...

এইচএফ ফাংশন যদি অবরুদ্ধ করে থাকে তবে তা কি পরবর্তী সময়গুলিতে কিছুটা বিলম্ব যোগ করবে না? সম্ভবত আপনি লাইনগুলিকে গোল করে নিতে পারেন যাতে হ্যান্ডেল_ফানশনটি প্রথমে টাইমার শুরু করে এবং তারপরে এইচএফচঞ্চনকে কল করে?
গোঁফ

2

একটি প্রকল্পের জন্য আমাকে এটি করতে হয়েছিল। আমি যা করে শেষ করেছি তা হ'ল ফাংশনের জন্য একটি পৃথক থ্রেড শুরু করা

t = threading.Thread(target =heartbeat, args=(worker,))
t.start()

**** হার্টবিট আমার ফাংশন, কর্মী আমার অন্যতম যুক্তি ****

আমার হার্টবিট ফাংশন ভিতরে:

def heartbeat(worker):

    while True:
        time.sleep(5)
        #all of my code

সুতরাং আমি যখন থ্রেডটি শুরু করব তখন ফাংশনটি বারবার 5 সেকেন্ড অপেক্ষা করবে, আমার সমস্ত কোড চালাবে এবং অনির্দিষ্টকালের জন্য এটি করবে। আপনি যদি প্রক্রিয়াটি হত্যা করতে চান তবে কেবল থ্রেডটি মেরে ফেলুন।


1

আমি এমন একটি ক্লাস প্রয়োগ করেছি যা টাইমার হিসাবে কাজ করে।

কারওর প্রয়োজন হলে আমি লিঙ্কটি এখানে রেখেছি: https://github.com/ivanhalencp/python/tree/master/xTimer


4
যতক্ষণ এই তাত্ত্বিক প্রশ্নের উত্তর হতে পারে, এটা বাঞ্ছনীয় হবে উত্তর অপরিহার্য অংশের এখানে অন্তর্ভুক্ত করা, এবং রেফারেন্স এর জন্য লিঙ্ক প্রদান।
কার্ল রিখটার

1
from threading import Timer
def TaskManager():
    #do stuff
    t = Timer( 1, TaskManager )
    t.start()

TaskManager()

এখানে ছোট নমুনা দেওয়া হয়েছে, এটি কীভাবে এটি চালায় তা বুঝতে সাহায্য করবে। ফাংশন টাস্ক ম্যানেজার () শেষে এটি নিজে থেকে বিলম্বিত ফাংশন কল তৈরি করে।

"ডালে" ভেরিয়েবল পরিবর্তন করার চেষ্টা করুন এবং আপনি পার্থক্য দেখতে সক্ষম হবেন

from threading import Timer, _sleep

# ------------------------------------------
DATA = []
dalay = 0.25 # sec
counter = 0
allow_run = True
FIFO = True

def taskManager():

    global counter, DATA, delay, allow_run
    counter += 1

    if len(DATA) > 0:
        if FIFO:
            print("["+str(counter)+"] new data: ["+str(DATA.pop(0))+"]")
        else:
            print("["+str(counter)+"] new data: ["+str(DATA.pop())+"]")

    else:
        print("["+str(counter)+"] no data")

    if allow_run:
        #delayed method/function call to it self
        t = Timer( dalay, taskManager )
        t.start()

    else:
        print(" END task-manager: disabled")

# ------------------------------------------
def main():

    DATA.append("data from main(): 0")
    _sleep(2)
    DATA.append("data from main(): 1")
    _sleep(2)


# ------------------------------------------
print(" START task-manager:")
taskManager()

_sleep(2)
DATA.append("first data")

_sleep(2)
DATA.append("second data")

print(" START main():")
main()
print(" END main():")

_sleep(2)
DATA.append("last data")

allow_run = False

4
আপনি আরও কিছু বলতে পারেন কেন এটি কাজ করে?
মিনোচা

আপনার উদাহরণটি কিছুটা বিভ্রান্তিকর ছিল, প্রথম কোডব্লকটি আপনাকে যা বলার দরকার ছিল তা ছিল।
পার্টাক

1

আমি রাইট 2 ক্লিকির উত্তরটি পছন্দ করি, বিশেষত এটিতে কোনও থ্রেড ছিন্ন করতে হবে না এবং প্রতিবার টাইমার টিক দেওয়ার সময় একটি নতুন তৈরি করা দরকার। তদাতিরিক্ত, এটি টাইমার কলব্যাক সহ একটি ক্লাস তৈরি করা একটি সহজ ওভাররাইড যা পর্যায়ক্রমে ডাকা হয়। এটি আমার সাধারণ ব্যবহারের কেস:

class MyClass(RepeatTimer):
    def __init__(self, period):
        super().__init__(period, self.on_timer)

    def on_timer(self):
        print("Tick")


if __name__ == "__main__":
    mc = MyClass(1)
    mc.start()
    time.sleep(5)
    mc.cancel()

1

এটি ক্লাসের পরিবর্তে ফাংশন ব্যবহার করে একটি বিকল্প বাস্তবায়ন। উপরে @ অ্যান্ড্রু উইলকিন্স দ্বারা অনুপ্রাণিত

কারণ অপেক্ষা ঘুমের চেয়ে আরও সঠিক (এটি ফাংশন রানটাইমটিকে অ্যাকাউন্টে গ্রহণ করে):

import threading

PING_ON = threading.Event()

def ping():
  while not PING_ON.wait(1):
    print("my thread %s" % str(threading.current_thread().ident))

t = threading.Thread(target=ping)
t.start()

sleep(5)
PING_ON.set()

1

আমি সিঙ্গেলন ক্লাসের সাথে আরও একটি সমাধান নিয়ে এসেছি। এখানে কোনও স্মৃতি ফুটো আছে কিনা তা আমাকে বলুন।

import time,threading

class Singleton:
  __instance = None
  sleepTime = 1
  executeThread = False

  def __init__(self):
     if Singleton.__instance != None:
        raise Exception("This class is a singleton!")
     else:
        Singleton.__instance = self

  @staticmethod
  def getInstance():
     if Singleton.__instance == None:
        Singleton()
     return Singleton.__instance


  def startThread(self):
     self.executeThread = True
     self.threadNew = threading.Thread(target=self.foo_target)
     self.threadNew.start()
     print('doing other things...')


  def stopThread(self):
     print("Killing Thread ")
     self.executeThread = False
     self.threadNew.join()
     print(self.threadNew)


  def foo(self):
     print("Hello in " + str(self.sleepTime) + " seconds")


  def foo_target(self):
     while self.executeThread:
        self.foo()
        print(self.threadNew)
        time.sleep(self.sleepTime)

        if not self.executeThread:
           break


sClass = Singleton()
sClass.startThread()
time.sleep(5)
sClass.getInstance().stopThread()

sClass.getInstance().sleepTime = 2
sClass.startThread()

0

থ্রেডস ব্যবহার করে উপরের দুর্দান্ত উত্তরের পাশাপাশি, আপনাকে যদি আপনার মূল থ্রেড ব্যবহার করতে হয় বা অ্যাসিঙ্ক পদ্ধতির পছন্দ করতে হয় - আমি আইও_টিমার টাইমার ক্লাসের চারপাশে একটি সংক্ষিপ্ত শ্রেণি আবৃত করেছি (পুনরাবৃত্তি সক্ষম করতে)

import asyncio
from aio_timers import Timer

class RepeatingAsyncTimer():
    def __init__(self, interval, cb, *args, **kwargs):
        self.interval = interval
        self.cb = cb
        self.args = args
        self.kwargs = kwargs
        self.aio_timer = None
        self.start_timer()
    
    def start_timer(self):
        self.aio_timer = Timer(delay=self.interval, 
                               callback=self.cb_wrapper, 
                               callback_args=self.args, 
                               callback_kwargs=self.kwargs
                              )
    
    def cb_wrapper(self, *args, **kwargs):
        self.cb(*args, **kwargs)
        self.start_timer()


from time import time
def cb(timer_name):
    print(timer_name, time())

print(f'clock starts at: {time()}')
timer_1 = RepeatingAsyncTimer(interval=5, cb=cb, timer_name='timer_1')
timer_2 = RepeatingAsyncTimer(interval=10, cb=cb, timer_name='timer_2')

ঘড়িতে শুরু হয়: 16024388 40 .9690785

টাইমার_ 1 16024388 45 .980087

টাইমার_ 2 16024388 50 .9806316

টাইমার_ 1 16024388 50 .9808934

টাইমার_ 1 16024388 55 .9863033

টাইমার_ 2 16024388 60 .9868324

টাইমার_ 1 16024388 60 .9876585

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.