Sending arguments to Python threads blocks other threads - python

Consider this test application for passing arguments to Python threads:
#!/usr/bin/python3
from pprint import pprint
import signal
import sys
import threading
class CallThreads(threading.Thread):
def __init__(self, target, *args):
self._target = target
threading.Thread.__init__(self)
target(*args)
def main(argv):
phrases = ['hello', 'goodbye']
num = 0
for phrase in phrases:
num += 1
thread_handler = CallThreads(someFunction, phrase, num)
thread_handler.daemon = True
thread_handler.start()
return True
def someFunction(a, b):
print("Hi: "+str(a)+" and "+str(b))
return True
def signal_handler(signal, frame):
print(["Got SIGINT!"])
sys.exit(0)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
main(sys.argv)
In it's current state, it seems as though the for phrase in phrases loop is waiting for the thread to finish before starting another thread. That is, if someFunction() takes a long time to complete, then the then next thread will not start until the previous thread returns. Why is this, and how can I work around it while still sending arguments to the threads?
Edit:
I've tried saving the args array in self._args in the constructor, and then calling self._target(*self._args) or self._target(self._args) in def run (self):. This actually works in Python 2, but not in Python 3. What should I do?
Edit:
It seems that the problem is that in Python 3, the run method cannot access the private variables. That is, for the following improved code:
def __init__(self, target, *args):
self._args = args
threading.Thread.__init__(self)
def run(self):
someFunction(*self._args)
Note the following output:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.3/threading.py", line 639, in _bootstrap_inner
self.run()
File "./test.py", line 19, in run
someFunction(*self._args)
TypeError: someFunction() missing 2 required positional arguments: 'a' and 'b'
And adding a pprint(self._args) to the run() method indeed shows that the tuple returned is empty. However, changing the variables to non-private works! The following code runs fine:
def __init__(self, target, *args):
self.target = target
self.args = args
threading.Thread.__init__(self)
def run(self):
self.target(*self.args)
Therefore, I can use the application with public variables in Python 3. However, is there any way to use private variables in the CallThreads class, as in Python 2?
Thanks!

The problem is that you call target(args) on the constructor of CallThreads.
Therefore the following call blocks until CallThreads.__init__() is finished:
thread_handler = CallThreads(someFunction, phrase, num)
Update:
One possibility could be the following:
class CallThreads(threading.Thread):
def __init__(self, *args):
self._args = args
threading.Thread.__init__(self)
def run(self):
someFunction(*self._args)

Related

Difficulties with call a method from a subclass in python - AttributeError: 'str' object has no attribute

I want to call a method in a subclass using threading. This method is a while loop that executes a method in the main class.
I don't understand the error, as I interpret it, I am doing something wrong with the inheritance.
A minimal example of my code:
class Echo(WebSocket):
def __init__(self, client, server, sock, address):
super().__init__(server, sock, address)
self.modbus = client
def temp_control(self, value)
do_something(value)
return True
class Temperature_Control3(Echo):
def __init__(self):
super().__init__()
self.value
def control(self, value):
while True:
print("temp_controll")
self.temp_control(self, value) #call the method in Echo class
time.sleep(4)
def main():
with ModbusClient(host=HOST, port=PORT) as client:
client.connect()
time.sleep(0.01)
print("Websocket server on port %s" % PORTNUM)
server = SimpleWebSocketServer('', PORTNUM, partial(Echo, client))
control = Temperature_Control3()
t3 = threading.Thread(target=control.control, args=('', 'get'), daemon=False)
t3.start()
try:
t1 = threading.Thread(target=server.serveforever())
t1.start()
for thread in threading.enumerate():
print(thread.name)
finally:
server.close()
t1 is starting well but t2 can't because of the error above. I have little experience with OOP programming, maybe someone here can help, thanks!
Edit: I got a new Error:
Traceback (most recent call last):
File "websocketserver6_threading.py", line 566, in <module>
main()
File "websocketserver6_threading.py", line 545, in main
control = Temperature_Control3()
File "websocketserver6_threading.py", line 516, in __init__
super().__init__()
TypeError: __init__() missing 4 required positional arguments: 'client', 'server', 'sock', and 'address'
One problem is that you're referring to Temperature_Controll3.temp_controll directly, which is the wrong way to do it.
Instead, you need to create an instance of that class:
t3 = Temperature_Controll3()
And then refer to the method of the instance:
target=t3.temp_controll
However, there are also other problems. The temp_controll() function is infinitely recursive:
def temp_controll(self, value):
while True:
print("temp_controll")
self.temp_controll(self, value)
time.sleep(4)
The function calls itself, which calls itself, which calls itself... forever. I have no idea what you're trying to do here.

Opposite of __init__ in thread class?

I understand that __init__() is called automatically when you create a class like newThread = MyThread(property) and run() is triggered by newthread.start(). What I am looking for is something that is called automatically before a thread terminates, so I don't have to explicitly call self.cleanUp() before each return statement.
class MyThread(Thread):
def __init__(self, property):
Thread.__init__(self)
self.property = property
def cleanUp(self):
# Clean up here
def run(self):
# Do some stuff
self.cleanUp() # Current work around
return
One way to do this is by making the Thread subclass also a context manager. This will effectively make __exit__() the special method you want triggered.
The following shows what I'm proposing. Note: I renamed the property argument you were passing the constructor because property is the name of a Python built-in.
from threading import Thread
import time
TEST_THREAD_EXCEPTION = False # change as desired
class MyThread(Thread):
def __init__(self, attribute):
Thread.__init__(self)
self.attribute = attribute
def cleanup(self):
# Clean up here
print(' cleaning up after thread')
def run(self):
if TEST_THREAD_EXCEPTION:
raise RuntimeError('OOPS!') # force exception
print(' other thread now running...')
time.sleep(2) # Do something...
def __enter__(self):
try:
self.run()
except Exception as exc:
print('Error: {} exception raised by thread'.format(exc))
raise # reraise the exception
return self
def __exit__(self, *args):
self.cleanup()
print('main thread begins execution')
with MyThread('hello') as thread:
print('doing other things in main thread while other thread is running')
print('main thread continuing...')
Output:
main thread begins execution
other thread now running...
doing other things in main thread while other thread is running
cleaning up after thread
main thread continuing on...
If you change TEST_THREAD_EXCEPTION to True, cleanup() won't be called since the thread didn't run successfully—although you could change that if you wished, but may also need to ensure that it doesn't get called twice. Here's what the code above does in that case:
main thread begins execution
Error: OOPS! exception raised by thread
Traceback (most recent call last):
File "opposite_init.py", line 37, in <module>
with MyThread('hello') as thread:
File "opposite_init.py", line 27, in __enter__
self.run()
File "opposite_init.py", line 21, in run
raise RuntimeError('OOPS!') # force exception
RuntimeError: OOPS!
As stated in the Python mailing list, __del__ shouldn't be considered the opposite, but you can use the with syntax, which is a context manager
you cannot be sure that an object's destructor (__del__() ) will ever
be called. If you want to make sure that a particular object gets
processed, one approach is the with- syntax.
Or you can also look into the try...finally clause, in which the finally statement will always get run.
class MyThread(Thread):
def __init__(self, property):
Thread.__init__(self)
self.property = property
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
print('starting cleanup')
# Clean up here
def run(self):
# Do some stuff
return
# not now you can call it like this:
with MyThread("spam") as spam:
print("The thread is running")
# you can also do stuff here
You can use the try...finally clause like so:
class MyThread(Thread):
def __init__(self, property):
Thread.__init__(self)
self.property = property
def cleanUp(self):
# Clean up here
print('starting cleanup')
def run(self):
# Do some stuff
return
try:
spam = MyThread('spam')
print('The thread is running')
finally:
spam.cleanUp()
If the problem you're trying to solve is that you don't want to add code to each of your run() methods to call your cleanup function, then I'd suggest making a custom subclass of Thread which does that for you. Something like this, perhaps:
class CleanupThread(Thread):
def cleanup(self):
# Override this method in your subclasses to do cleanup
pass
def run2(self):
# Override this method in your subclasses instead of run()
pass
def run(self):
# Do *not* override this in your subclasses. Override run2() instead.
try:
self.run2()
finally:
self.cleanup()
Of course, you're free to rename run2 to something that makes sense for you.
Python does not offer a built-in equivalent of this, if that's what you're looking for.

call function x number of times and execute it from another script

I am running 2 python scripts, say main.py and test.py
In main.py i am executing get_details function "x" number of times every 30 seconds.
NOTE: I want to execute funA,funcB funC in sequence. The issue i am facing here is - when i run test.py, it first runs funcC(), even though i am calling funcA() first.
test.py
def funcA():
#do something
funcB()
def funcB():
#do something
funcC()
def funcC():
#here i want to execute script main.py
#My attempt 1 :
import subprocess
import sys
theproc = subprocess.Popen([sys.executable, "main.py"])
theproc.communicate()
#------OR-----------
#My attempt 2:
execfile("main.py")
main.py
import threading
def get_details(a,b,c):
#do something ...
class RepeatEvery(threading.Thread):
def __init__(self, interval, func, *args, **kwargs):
threading.Thread.__init__(self)
self.interval = interval # seconds between calls
self.func = func # function to call
self.args = args # optional positional argument(s) for call
self.kwargs = kwargs # optional keyword argument(s) for call
self.runable = True
def run(self):
while self.runable:
self.func(*self.args, **self.kwargs)
time.sleep(self.interval)
def stop(self):
self.runable = False
thread = RepeatEvery(30, get_details,"arg1","arg2","arg3")
print "starting"
thread.start()
thread.join(21) # allow thread to execute a while...
I want to execute script main.py only after all functions (funcA,funcB) executed properly. But in my case, main.py executed first and then control goes back to test.py and it executes funcA() and funcB().
What am i missing here ?
Okay. I rewrote your code so it would work as you said it should.
main.py...
#Good design for small classes: keep global functions separate for people who want
#to explore the type, but not everything that comes along with it.
#I moved the the global functions and code execution from top and bottom to test.py
import threading
import time #You forgot to import time.
class RepeatEvery(threading.Thread):
def __init__(self, interval, func, *args, **kwargs):
threading.Thread.__init__(self)
self.interval = interval # seconds between calls
self.func = func # function to call
self.args = args # optional positional argument(s) for call
self.kwargs = kwargs # optional keyword argument(s) for call
self.runable = True
def run(self):
while self.runable:
self.func(*self.args, **self.kwargs)
time.sleep(self.interval)
def stop(self):
self.runable = False
""" We couuuld have done this, but why bother? It is hard to work with.
def get_details(self,a,b,c):
#do something else as a function of the class...
"""
test.py...
import main #File where class lives.
def funcA():
#do something
print ("In A...") #Helps us observe scope.
funcB()
def funcB():
#do something
print("In B...") #scope
funcC()
def funcC():
#here i want to execute script main.py
#My attempt 1 :
print("In C...") #scope
main() #Reached C, lets run main now...
#This is one way to do allow a function to be accessible to your class.
def get_details(a,b,c):
#do something else as a function of ¬[class] test.py operating on
#a RepeatEvery object...
pass
def main(): #Function main is separate from class main. It houses our opening code.
thread = main.RepeatEvery(30, get_details,"arg1","arg2","arg3")
print ("starting")
thread.start()
thread.join(21) # allow thread to execute a while...
funcA()

How to call __init__ method of the parent class after dynamic class creation in Python?

I want dynamically create a class from two Base classes (ExampleTestRun and Thread). Main purpose for this is to start ExampleTestRun method "run" in a thread (by calling Thread class method "start"). I never used super() in Python. Maybe with it would be an answer?
from threading import Thread
class BaseTest(object):
def __init__(self):
pass
class ExampleTestRun(BaseTest):
def run(self):
try:
a = int('A')
except Exception as ex:
print ex
if __name__ == "__main__":
test_class = type('TestClass', (ExampleTestRun, Thread), {})
test = test_class()
test.start()
I got error:
Traceback (most recent call last):
File "D:/Dropbox/Workspaces/PyCharmWorkspace/ElgsisTests/src/mcltests/mcltransparent/run.py", line 30, in <module>
test.start()
File "C:\Python27\lib\threading.py", line 737, in start
raise RuntimeError("thread.__init__() not called")
RuntimeError: thread.__init__() not called
It throws that error becuase you are overriding the __init__ of the newly created class. Replacing that re-definition with pass altogether will fix it:
class BaseTest(object):
pass
Of course if you want to expand on the original constructor, you will have to resort to super. So the full code will look like this:
from threading import Thread
class BaseTest(object):
def __init__(self):
super(BaseTest, self).__init__()
class ExampleTestRun(BaseTest):
def run(self):
try:
a = int('A')
except Exception as ex:
print ex
if __name__ == "__main__":
test_class = type('TestClass', (ExampleTestRun, Thread), {})
test = test_class()
test.start()

Python multiprocessing - probably failure when method name pass to Process

I have problem with multiprocessing. Under you have the code (he's in couple of class and files, but i simplified it).
I suppose, that problem lies in pass method name which I want to multiply in multiprocessing.
Informations:
"args" is a list like as [(0,1),(1,2),(2,3)] so single "arg" like as (0,1)
This two files are in totally other calatogs
!!First file!!
from ... import EF
from ... import someclass
class performs():
def action():
for i, arg in enumerate(args):
data.append(EF(self.method,list(arg),i))
someclass.create_processes(*data)
def method(self,fa,la):
...
!!second file!!
from multiprocessing import Process,Event
class EF(object):
def __init__(self,name,args=list(),proc=1):
self.name=name
self.args=args
self.proc=proc
class someclass:
#staticmethod
def create_processes(*functions):
processes=dict()
for function in functions:
process=Process(target=function.name,args=function.args)
process.start()
processes[process.pid]=process
for process in processes.values():
process.join()
When I'm debugging, error comes, when program performing this instruction "process.start()"
Console:
File "C:\Python32\lib\multiprocessing\forking.py", line 371, in main
self = load(from_parent)
AttributeError: 'performs' object has no attribute 'function'
or in other situation
File "C:\Python32\lib\multiprocessing\process.py", line 267, in _bootstrap
self.run()
File "C:\Python32\lib\multiprocessing\process.py", line 116, in run
self._target(*self._args, **self._kwargs)
File "...\performs.py", line 88, in method
...
I don't know it's important, but I have 64bit system, and installed Python and accesories for 32 bit
The comment box is too small for this, but it seems like your code is working fine. I tested it by copying it in two files (like your environment), but it of course also works in a single file. That file you can find below: it is working as expected (save for the print statements output being mixed up, but that is to be expected).
So, most likely, your issue lies elsewhere? The error seems to indicate perhaps some inclusion order, like stated in this question?
from multiprocessing import Process,Event
class EF:
def __init__(self, name, args=list(), proc=1):
self.name = name
self.args = args
self.proc = proc
class someclass:
#staticmethod
def create_processes(*functions):
processes=dict()
for function in functions:
process=Process(target=function.name,args=function.args)
process.start()
processes[process.pid]=process
for process in processes.values():
process.join()
class performs:
def action(self, args):
data = []
for i, arg in enumerate(args):
data.append(EF(self.mult, list(arg), i))
someclass.create_processes(*data)
def mult(self,fa,la):
print '%d x %d = %d' % (fa, la, fa * la)
if __name__ == '__main__':
p = performs()
p.action([(x, x+1) for x in xrange(10)])

Categories