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.
Related
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
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")
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.)
I've been playing along with threads in Python, and I came across something interesting with the following code:
import time
import threading
class Update(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop_event = threading.Event()
def join(self, timeout=None):
self.stop_event.set()
threading.Thread.join(self, timeout)
def run(self):
while not self.stop_event.isSet():
print("test")
thread = Update()
thread.start()
This code randomly stops even if I don't call the join() method. As a result, I get different outputs like these:
test#debian:~/$ python3 test.py
test
test
test
test
test#debian:~/$ python3 test.py
test
test
test
test
test
test
test
test#debian:~/$ python3 test.py
test
test
Why is this code randomly stopping? I thought that only by setting stop_event this thread would stop.
You already got the essential answer, but there's a detail you need to be aware of: when the main program ends, as part of shutdown processing Python calls .join() on all non-daemon threads created by the threading module. You overrode .join(), so Python calls your .join(). That in turn sets the event, and so your .run() method exits silently.
When the main thread ends the program ends.
The number of times that the thread loops before the main one stops is fairly arbitrary. (up to the OS to schedule)
I've a python scheduler code to print Hello and World!.
import sched
import time
def x():
print "Hello"
s = sched.scheduler(time.time, time.sleep)
s.enter(10, 1, x, ())
s.run()
print "World!"
This waits for 10 seconds and outputs:
Hello
World!
I think a scheduler's job is to schedule a task without interrupting the current process. But here it's putting the whole program to sleep and behaves just like the below code:
import time
def x():
print "Hello"
time.sleep(10)
x()
print "World!"
I guess the scheduler makes the program to sleep due to the time.sleep parameter in sched.scheduler(time.time, time.sleep).
Is there anyway we can make it work just like a real-time scheduler without blocking the main process without using any multithreading or multiprocessing?
From the docs:
In multi-threaded environments, the scheduler class has limitations with respect to thread-safety, inability to insert a new task before the one currently pending in a running scheduler, and holding up the main thread until the event queue is empty. Instead, the preferred approach is to use the threading.Timer class instead.
from threading import Timer
def x():
print "Hello"
Timer(10, x, ()).start()
print "World!"
without blocking the main process without using any multithreading or multiprocessing
A single thread can't be doing two things at the same time, so... threading is the absolute minimum you need to use in order not to block.
The scheduler's job is to not only execute the subsequent tasks after every particular time period. its job is also to lock the object until it completes its task.
from threading import Timer
def xy():
print("End")
Timer(4, xy, ()).start()
print ("Start")
Initially, Start will be printed, then 4 sec later End will be printed.
What if we have an endless loop
from threading import Timer
def xy():
print("End")
Timer(4, xy, ()).start()
print("Start")
i = 0
while i < 10:
print(i)
It will be running continuously. Hence, It is proved that it will hold the thread until the prev one completes its task.