Multithreading Keep threads active - python

I am struggling with multi threading my code. I want to ALWAYS have 10 active threads, but I am not sure how.
Current code:
import threading
from random import randint
import os
import names
import random
import time
threads = 10
def f():
print("my actual function is 200+ lines")
return
for i in range(threads):
t = threading.Thread(target=f)
t.start()
My current code starts 10 threads, but does not maintain them, keep active. Thank you for the help
edit: have also tried with while True, but no luck.

To keep your loops active, you should have a loop in your thread function as you said. But in this piece of code there is a return callback that will exit from your loop after print. You should write somethings like this:
def f():
while True:
print("my actual function is 200+ lines")
And if you want to manage your thread to stop sometimes, you should write a stop function and use a Boolean flag to control your while loop (instead of while True).
thread_status = True
def stopThread():
thread_status = False
def f():
while thread_status:
print("my actual function is 200+ lines")

Related

Python - track (catch) variable changes in imported (instantiated) Class from another file (sensors readings)

I have a script, let's say "sensors.py" in which I have a Class "Meas", that reads measurements from several sensors. These comes from serial ports, program makes some calculations on them and changes the class "self.variable_a value" and another self variables also. The readings are in continuous mode, i.e. the program automatically waits for a message to come from the sensor to the serial port and read whole line (it's done via pyserial library). Some transmit readings at frequency of 10Hz, others 20Hz or 100Hz. This is a really big and messy class, therefore I put it in a separate file.
In my "main.py" script I import this "sensors" file and instantiate the "Meas" Class. Now I have a problem. How can I run immediately some "on_changed_var_a" function in "main" script, only when the "variable_a" in "Meas" object has changed - without consuming CPU power with while loop (constatly checking whether by any chance the variable has not changed) or waiting with time.sleep()? I need to get the sensors readings changes and then run another functions in "main" script in the most efficient way, as fast as possible. Thanks in advance!
EDIT: added example files
"sensors.py" file:
import random
import time
import threading
running = True
class Meas1:
def __init__(self, xyz):
self.xyz = xyz
self.var_a = None
thr1 = threading.Thread(target=self.readings, daemon=True)
thr1.start()
def readings(self):
while running:
# simulating 5Hz sensor readings:
self.var_a = self.xyz * random.randint(1, 1000)
print(self.var_a)
time.sleep(0.2)
"main.py" file:
import time
import sensors
import threading
class MainClass:
def __init__(self):
print("started")
self.sensor1 = sensors.Meas1(xyz=7)
thr_ksr = threading.Thread(target=self.thr_keep_script_running, daemon=True)
thr_ksr.start()
# in this part I would like to run the on_changed_var_a function, immediately when var_a changes
thr_ksr.join()
def on_changed_var_a(self):
print("var_a changed: ", self.sensor1.var_a)
def thr_keep_script_running(self, t=10):
time.sleep(t)
sensors.running = False
print("stopped, sleeping 1 sec")
time.sleep(1)
mc = MainClass()
Not sure why this is tagged mutithreading. You need this function to be run on different thread?
To the problem. The easiest way would be to make Meas call function you will pass to it.
You could make variable_a a property and then in it's setter call the function you want. Function could be passed and assigned to self.call_on_a_change attr for example.
Edit:
I don't think there is a way to make function execute on different thread (well, you could start a new one for that purpose, which sounds like a great solution to me).
Another problem with threads is that you give control to the system. It decides when and for how long which thread runs. So "as fast as possible" is constrained by that.
Nonetheless, you could create a threading.Lock and try to acquire it from main thread. Then in the reading thread upon change you could release the Lock and allow main thread to execute all call_on_a_change. Something like this:
import time
import threading
lock = threading.Lock()
# change to locked
lock.acquire()
a_change_callbacks = []
def on_changed_var_a(new_a):
print(new_a)
def readings():
a_change_callbacks.append(lambda: on_changed_var_a('first `a` change'))
lock.release()
time.sleep(5)
a_change_callbacks.append(lambda: on_changed_var_a('second `a` change'))
lock.release()
time.sleep(5)
a_change_callbacks.append(lambda: on_changed_var_a('third `a` change'))
lock.release()
thr = threading.Thread(target=readings, daemon=True)
thr.start()
while True:
lock.acquire()
for callback in list(a_change_callbacks):
callback()
a_change_callbacks.remove(callback)
if not thr.is_alive():
break
It's not your class model, but I hope it's enough to show the idea :D

How to run a recursive function within a thread?

I wanted to run a function repeating itself while my main code (I guess it is called main thread) is still running so I did this, there is probably a better way of doing this but I am new to coding and python so I have no idea what am I doing.
import threading
import time
def x():
print("hey")
time.sleep(1)
x()
t = threading.Thread(target=x)
t.daemon = True
t.start()
when I make daemon False it repeats itself but when I stop the program I get an error
CPython (the reference implementation of Python) does not implement Tail Call Optimization (TCO).¹ This means you can't run excessive recursion since it is limited and you would get a RuntimeError when you hit this limit.
sys.getrecursionlimit() # 3000
So instead of calling x() from within x() again, make a while True-loop within x():
import threading
import time
def x():
while True:
print("hey")
time.sleep(1)
t = threading.Thread(target=x, daemon=True)
t.start()
time.sleep(10) # do something, sleep for demo
¹ Stackless Python would be a Python implementation without recursion limit.

Threading target function runs only one loop

I am trying to run a function in the background till some work is done in the main function and then finish the thread. I have implemented the threading logic in a separate class and the main in another file. But every time I run it the target function only seems to run once and then waits
Here is the main function
from ThreadRipper import *
thread_obj=ThreadRipper()
thread_obj.start_thread()
squish.snooze(10)
print("Main Continuing")
thread_obj.stop_thread()
And the implemented class is as follows
class ThreadRipper():
def __init__(self):
lib_path="iCOMClient.dll"
self.vx = IcomVx(lib_path)
config = ConfigParser.SafeConfigParser(allow_no_value=True)
config.readfp(open("vx_logger_config.cfg"))
self.vx.connect(config.get("icom","ip"), timeout_millis = 30000)
self.t = threading.Thread(target=self.task_to_do, args=(self.vx,))
def stop_thread(self):
self.t.do_run=False
self.t.join()
def start_thread(self):
self.t.start()
def task_to_do(self,arg):
current_thread=threading.currentThread()
while getattr(current_thread,"do_run",True):
with open("vx.txt",'a') as f:
f.write(str(arg.get_next_message()._rawmsg)+"\n")
time.sleep(1)
print("Stopping")
arg.disconnect()
When I run this I get the vx file created but with only one entry, I expect it to be written to continuously till the while loop exits. I am quite new at threading and may have understood it incorrectly. Please advise
Thank you
The reason is probably because
print("Stopping")
arg.disconnect()
are both inside the while loop. After disconnecting, arg doesn't seem to produce any more messages.
(Unless, of course, your code in the question is not what you really have, but in this case, you surely would have edited your question so it matches.)

How to read users input when in loop (and without blocking work in this loop)?

How to read users input when in loop (and without blocking work in this loop)?
I want to do some basic stuff, like switching DEBUG variable, print values of some variables etc on some specific keys that user will print, but my program work in constant loop, and this loop fire another threads. How can i do this?
Use threads:
import threading
import time
value = 3
def process():
while True:
print(value)
time.sleep(1)
thread = threading.Thread(target=process)
thread.start()
while True:
value = input('Enter value: ')
(Output gets kind of messed up here because of both loops printing stuff to the terminal but I think the idea should be clear.)

making a programme run indefinitely in python

Is there any way to make a function (the ones I'm thinking of are in the style of the simple ones I've made which generate the fibonnacci sequence from 0 to a point, and all the primes between two points) run indefinitely. E.g. until I press a certain key or until a time has passed, rather than until a number reaches a certain point?
Also, if it is based on time then is there any way I could just extend the time and start it going from that point again, rather than having to start again from 0? I am aware there is a time module, i just don't know much about it.
The simplest way is just to write a program with an infinite loop, and then hit control-C to stop it. Without more description it's hard to know if this works for you.
If you do it time-based, you don't need a generator. You can just have it pause for user input, something like a "Continue? [y/n]", read from stdin, and depending on what you get either exit the loop or not.
If you really want your function to run and still wants user (or system) input, you have two solutions:
multi-thread
multi-process
It will depend on how fine the interaction. If you just want to interrupt the function and don't care about the exit, then multi-process is fine.
In both cases, you can rely on some shared resources (file or shared memory for multi-thread, variable with associated mutex for multi-thread) and check for the state of that resource regularly in your function. If it is set up to tell you to quit, just do it.
Example on multi-thread:
from threading import Thread, Lock
from time import sleep
class MyFct(Thread):
def __init__(self):
Thread.__init__(self)
self.mutex = Lock()
self._quit = False
def stopped(self):
self.mutex.acquire()
val = self._quit
self.mutex.release()
return val
def stop(self):
self.mutex.acquire()
self._quit = True
self.mutex.release()
def run(self):
i = 1
j = 1
print i
print j
while True:
if self.stopped():
return
i,j = j,i+j
print j
def main_fct():
t = MyFct()
t.start()
sleep(1)
t.stop()
t.join()
print "Exited"
if __name__ == "__main__":
main_fct()
You could use a generator for this:
def finished():
"Define your exit condition here"
return ...
def count(i=0):
while not finished():
yield i
i += 1
for i in count():
print i
If you want to change the exit condition you could pass a value back into the generator function and use that value to determine when to exit.
As in almost all languages:
while True:
# check what you want and eventually break
print nextValue()
The second part of your question is more interesting:
Also, if it is based on time then is there anyway I could just extend the time and start it going from that point again rather than having to start again from 0
you can use a yield instead of return in the function nextValue()
If you use a child thread to run the function while the main thread waits for character input it should work. Just remember to have something that stops the child thread (in the example below the global runthread)
For example:
import threading, time
runthread = 1
def myfun():
while runthread:
print "A"
time.sleep(.1)
t = threading.Thread(target=myfun)
t.start()
raw_input("")
runthread = 0
t.join()
does just that
If you want to exit based on time, you can use the signal module's alarm(time) function, and the catch the SIGALRM - here's an example http://docs.python.org/library/signal.html#example
You can let the user interrupt the program in a sane manner by catching KeyboardInterrupt. Simply catch the KeyboardInterrupt exception from outside you main loop, and do whatever cleanup you want.
If you want to continue later where you left off, you will have to add some sort persistence. I would pickle a data structure to disk, that you could read back in to continue the operations.
I haven't tried anything like this, but you could look into using something like memoizing, and caching to the disk.
You could do something like this to generate fibonnacci numbers for 1 second then stop.
fibonnacci = [1,1]
stoptime = time.time() + 1 # set stop time to 1 second in the future
while time.time() < stoptime:
fibonnacci.append(fibonnacci[-1]+fibonnacci[-2])
print "Generated %s numbers, the last one was %s." % (len(fibonnacci),fibonnacci[-1])
I'm not sure how efficient it is to call time.time() in every loop - depending on the what you are doing inside the loop, it might end up taking a lot of the performance away.

Categories