Posts: 12,024
Threads: 484
Joined: Sep 2016
Jan-03-2017, 01:15 PM
(This post was last modified: Jan-03-2017, 01:48 PM by Larz60+.)
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()
Posts: 12,024
Threads: 484
Joined: Sep 2016
Jan-03-2017, 05:32 PM
(This post was last modified: Jan-03-2017, 09:45 PM by Larz60+.)
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()
Posts: 12,024
Threads: 484
Joined: Sep 2016
Jan-03-2017, 10:50 PM
(This post was last modified: Jan-03-2017, 10:50 PM by Larz60+.)
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()
Posts: 1,150
Threads: 42
Joined: Sep 2016
Thanks a lot, I will give it a spin!
Posts: 1,150
Threads: 42
Joined: Sep 2016
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.
Posts: 12,024
Threads: 484
Joined: Sep 2016
Jan-09-2017, 07:28 PM
(This post was last modified: Jan-09-2017, 07:29 PM by Larz60+.)
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.
Posts: 1,150
Threads: 42
Joined: Sep 2016
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.
Posts: 12,024
Threads: 484
Joined: Sep 2016
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.
|