Python Forum
Stopping scheduler with condition
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Stopping scheduler with condition
#11
I'll have to scratch my butt a bit in order to figure out where the hair-brained idea came from
It looks like I used the timeout as my clock.

This is not quite there, perhaps you can fix it.
I need to take about a three hour nap (happens when you get old), then I'll be back
This is close to being right
#
# Author: Larry McCaig (Larz60+)
# No warranty, use at your own risk!
# Modify if you wish
#
import threading


class EventTimer:
    '''
    Creates overlaping threaded timed events
    Events can be set to trigger in days, hours, minutes, and/or seconds
    Any number of events can be created, and are treated independently, thus can
    overlap each other.
    Program execution will continue until all events have completed.
    the function that is passed to each timer will execute after the timeout has
    been reached
    '''

    def __init__(self):
        self.threadList = []

    def addEvent(self, func, days=0, hours=0, minutes=0, seconds=0, new=False):
        if new:
            self.threadList = []
        times = [days, hours, minutes, seconds]
        multiplier = [86400, 3600, 60, 1]
        count = 0

        for n in range(len(times)):
            count += times[n] * multiplier[n]

        t = threading.Timer(count, func)
        self.threadList.append(t)

    def startAll(self):
        # Start threads
        [th.start() for th in self.threadList]

    def waitForFinish(self):
        # wait for all to finish
        [th.join() for th in self.threadList]

class MyTimedEvent(EventTimer):
    def __init__(self, num_iters=1, seconds=0):
        self.num_iterations_so_far = 0
        self.num_iters = num_iters
        self.seconds = seconds
        self.kick_off_event()

    def kick_off_event(self):
        self.addEvent(self.event_triggered, seconds=self.seconds, new=True)

    def event_triggered(self):
        self.num_iters -= 1
        if self.num_iters:
            kick_off_event()
        self.timed_event()

    def timed_event(self):
        self.num_iterations_so_far += 1
        print('Processed {}'.format(self.num_iterations_so_far))

def launch():
    mte = MyTimedEvent(num_iters=8, seconds=10)
    mte.kick_off_event()
    mte.waitForFinish()


if __name__ == '__main__':
    launch()
Reply
#12
The following works for your situation, but breaks the multi tasking (since I re-initialize the thread list).
It needs more work, but can be used temporarily.
I also fixed PEP 8 Issues
#
# Author: Larry McCaig (Larz60+)
# No warranty, use at your own risk!
# Modify if you wish
#
import threading


class EventTimer:
    """
    Creates overlaping threaded timed events
    Events can be set to trigger in days, hours, minutes, and/or seconds
    Any number of events can be created, and are treated independently, thus can
    overlap each other.
    Program execution will continue until all events have completed.
    the function that is passed to each timer will execute after the timeout has
    been reached
    """

    def __init__(self):
        self.threadList = []

    def add_event(self, func, days=0, hours=0, minutes=0, seconds=0, new=False):
        if new:
            self.threadList = []
        times = [days, hours, minutes, seconds]
        multiplier = [86400, 3600, 60, 1]
        count = 0

        for n in range(len(times)):
            count += times[n] * multiplier[n]

        t = threading.Timer(count, func)
        self.threadList.append(t)

    def start_all(self):
        # Start threads
        [th.start() for th in self.threadList]

    def wait_for_finish(self):
        # wait for all to finish
        [th.join() for th in self.threadList]


class MyTimedEvent(EventTimer):
    def __init__(self, max_iters=1, seconds=0):
        super().__init__()
        self.num_iterations_so_far = 0
        self.max_iters = max_iters
        self.seconds = seconds

    def kick_off_event(self):
        self.add_event(self.event_triggered, seconds=self.seconds, new=True)
        self.start_all()

    def event_triggered(self):
        self.max_iters -= 1
        print('T minus {}'.format(self.max_iters))
        if self.max_iters:
            self.kick_off_event()


def launch():
    mte = MyTimedEvent(max_iters=8, seconds=2)
    mte.kick_off_event()
    mte.wait_for_finish()


if __name__ == '__main__':
    launch()
The following is my initial attempt at a new timer class that allows for recurring tasks - I haven't implemented the code that
will start and restart the timer threads yet - still thinking about this one and open for all suggestions
#
# Author: Larry McCaig (Larz60+)
# No warranty, use at your own risk!
# Modify if you wish
#
import threading


class EventTimer:
    """
    Creates overlapping threaded timed events
    Events can be set to trigger in days, hours, minutes, and/or seconds
    Any number of events can be created, and are treated independently, thus can
    overlap each other.
    Program execution will continue until all events have completed.
    the function that is passed to each timer will execute after the timeout has
    been reached
    """

    def __init__(self):
        self.threadList = []

    def add_event(self, func, days=0, hours=0, minutes=0, seconds=0, recurring=False, max_iters=1):
        times = [days, hours, minutes, seconds]
        multiplier = [86400, 3600, 60, 1]
        count = 0

        for n in range(len(times)):
            count += times[n] * multiplier[n]

        t = threading.Timer(count, func)
        self.threadList.append((t, recurring, max_iters))

    def start_all(self):
        # Start threads
        [th.start() for th in self.threadList]

    def wait_for_finish(self):
        # wait for all to finish
        [th.join() for th in self.threadList]

    def show_threadlist(self) -> object:
        n = 0
        for t, recurring, max_iters in self.threadList:
            print('Index: {}, thread: {}, recurring: {} max_iters: {}'.format(
                n, t, recurring, max_iters))
            n += 1
        return None


def function1():
    print('Function 1 triggered')


def function2():
    print('Function 2 triggered')


def function3():
    print('Function 3 triggered')

def launch():
    e = EventTimer()
    e.add_event(function1, seconds=5)
    e.add_event(function2, seconds=10)
    e.add_event(function3, seconds=2, recurring=True, max_iters=5)
    e.show_threadlist()


if __name__ == '__main__':
    launch()
Reply
#13
Here's a finished module, that will do what you want.

import threading


class EventTimer:
    def __init__(self):
        self.t = None

    def add_event(self, func, days=0, hours=0, minutes=0, seconds=0):
        times = [days, hours, minutes, seconds]
        multiplier = [86400, 3600, 60, 1]
        count = 0

        for n in range(len(times)):
            count += times[n] * multiplier[n]

        self.t = threading.Timer(count, func)

    def start_thread(self):
        self.t.start()

    def wait_for_finish(self, timeout=None):
        self.t.join(timeout)
        self.t = None


class MyTimer(EventTimer):
    def __init__(self, max_iters=1, seconds=0):
        super().__init__()
        self.num_iterations_so_far = 0
        self.max_iters = max_iters
        self.seconds = seconds

    def kick_off_event(self):
        self.add_event(self.event_triggered, seconds=self.seconds)
        self.start_thread()

    def event_triggered(self):
        self.max_iters -= 1
        print('T minus {}'.format(self.max_iters))
        if self.max_iters > 0:
            self.kick_off_event()


def try_timer():
    mte = MyTimer(max_iters=8, seconds=2)
    mte.kick_off_event()
    mte.wait_for_finish()


if __name__ == '__main__:
    try_timer()
Reply
#14
Thanks a lot, I will give it a spin!
Reply
#15
I have put your code in a separate Python file (which I import as a module in my "executable" .py file), with slight modifications:
I added:
"def __init__(self, function, max_iters=1, seconds=0)"
and replaced
"print('T minus {}'.format(self.max_iters))" with a call to function I would like to execute with the timer:
function()

Of course "function" is defined in the separate file with main code to be executed, so there is an unresolved reference. What would be a good way around this? Obviously I could put the Timer definitions you wrote in the same file as the rest of the code. But I would like to keep it clear and modular if possible.
Reply
#16
I should have made this clear in the previous post, but was lazy. The myTimer class was only written as an example of how to use the EventTimer class
The only part of this code that needed to  be in the module was the Event Timer class.

Glad that the example code came close to what you needed.

To be complete, I should create a stop method.
Reply
#17
That's fine, I understand now, indeed your code is a great example. It was me rather who was being lazy and thought the code might do all I need magically.
Code got very close to what I need, so thanks again for sharing it.
Sure, if you'll be in the mood for creating the stop method as well I will appreciate it.
Reply
#18
I started looking at a stop method, here's what I discovered:

Quote:Timer.cancel()¶

    Stop the timer, and cancel the execution of the timer’s action. This will only work if the timer is still in its waiting stage.


So I guess it can be added, but can't be canceled if the thread has been kicked off.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Question Running Python script through Task Scheduler? Winfried 8 461 Mar-10-2024, 07:24 PM
Last Post: Winfried
  stopping number conversion before end Skaperen 6 2,987 Jul-12-2020, 09:22 AM
Last Post: DeaD_EyE
  Stopping a loop in another file catosp 4 2,651 Jun-15-2020, 02:45 PM
Last Post: catosp
  else condition not called when if condition is false Sandz1286 10 5,840 Jun-05-2020, 05:01 PM
Last Post: ebolisa
  [HELP] Nested conditional? double condition followed by another condition. penahuse 25 7,894 Jun-01-2020, 06:00 PM
Last Post: penahuse
  how to cancel scheduler module event nanok66 0 2,133 May-11-2020, 10:31 PM
Last Post: nanok66
  Getting an .exe to run from Task Scheduler fioranosnake 2 3,009 Dec-06-2019, 12:20 PM
Last Post: DeaD_EyE
  Simple mutli-threaded scheduler using sched - stuck Mzarour 2 6,113 Nov-12-2019, 07:44 PM
Last Post: Mzarour
  Batch file not running python script in task scheduler davork 3 4,508 May-09-2019, 12:53 PM
Last Post: Gribouillis
  Help with Stopping a function after a timer SheeppOSU 0 1,928 Jan-28-2019, 10:13 PM
Last Post: SheeppOSU

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020