now that i have some threading working, i’m building some simple logic and was wondering if leaving a thread to just idle in an if..then
loop has any real negative performance cost? to whit, if the check fails, the thread does no work, but continues to check in the event the check succeeds. the expectation is that the thread will run virtually in-perpetuity, restarting only on device power cycle, which ranges from bi-weekly, to quarterly. even as i type this, i think it’s a stupid question, but i can’t leave any stone unturned because i’m new to threading in Python.
If what you mean by “leaving the thread idle in a loop” is anything like this:
while True:
if some_variable:
break
Then this is not idling at all, this will consume the full power of your Python application in a certain sense. If you want to make a thread wait on a condition to happen, take a look at threading.Event
.
nope. like this:
while True:
if thing == 'banana':
# do stuff
the idea being, the thread doesn’t really do anything until the flag is changed. i’ll look @ threading.Event
though. but i am curious about the impact of the above.
Still a busy loop. It will continuously check the condition.
okay. i thought so. but wanted to confirm. is that not similar to waiting for the event though? same cycles, no? or is that different?
No, when you wait for an event, there is no loop. One thread will simply call event.wait()
, which will block until the event is set. Blocking the waiting thread is what you want: instead of the thread repeatedly asking “are we there yet? what about now?” (which consumes computing power), it will be put to sleep and will be waken up when the event is set. This means that, at some time, in some other thread, you will have to call event.set()
.
ooooh! this is very useful information! thank you! but it kicks my trike in the ditch because i have to do some rewriting… can i just not work today and have it magically be done? off to the docs!!
so, if i am understanding what you said, with my threads, there’s a kind of central-management thread that calls event.set()
while my other ‘worker’ threads start with event.wait()
… and that management thread can be part of the MQTT on_message
callback (which is what handles user interaction) and that kicks off the required threads, yes? if i understand this right, this is actually not that bad.
thank you!
presume this is toggle-able behaviour?
It’s not clear to me what exactly you are assuming is togglable.
okay. that’s looks a heck of a lot more elegant than i was anticipating. thank you very much. from what i gleaned, i’ve been tinkering:
import time
import threading
import random
inputSignal = False
def worker_function():
print(3*f'-----------> working ')
def worker_thread(delay, event):
#worker.wait() #<-- this is only good until it enters the loop... duh...
while True:
worker.wait() #<-- if this is NOT set, it bails right here
time.sleep(delay)
worker_function()
def manage_function(event):
print(f'\n|| inside management ||')
global inputSignal
if inputSignal: #<--toggles the worker thread
worker.set()
print(f'=== worker enabled ===')
else:
worker.clear()
print(f'=== worker disabled ===')
def management_thread(delay, event):
while True:
time.sleep(delay)
manage_function(event)
def signalClock(interval):
while True:
time.sleep(interval)
getInputSignal()
def getInputSignal():
global inputSignal
inputSignal = True if random.randint(0, 1) else False
print(f'\n►► inputSignal: {inputSignal} ◄◄\n')
return inputSignal
worker = threading.Event()
threading.Thread(target=worker_thread, args=(0.25, worker)).start()
threading.Thread(target=management_thread, args=(1.0, worker)).start()
threading.Thread(target=signalClock, args=(0.5,)).start()
while True: #<-- main application loop
time.sleep(0.1)
print(f'main loop')
once the worker thread starts, when the worker.clear()
is called, it doesn’t go back to waiting. what am i doing wrong? according to the docs, this should work:
clear()
Reset the internal flag to false. Subsequently, threads callingwait()
will block untilset()
is called to set the internal flag to true again.
EDIT: turns out, i put the worker.wait()
outside the loop instead of instead of inside the loop. i corrected the code to reflect this and commented the wrong line for contrast. and, of course, because of the different timings, it will take a few loops to pick up the change.
massive thanks to you guys for your helpful nudges. got me thinking, and thinking in the right direction.