I'm new to Python so please bear with my question.
Let's say my application has a module named message_printer which simply defines a print_message function to print the message. Now in my main file, I create two threads which calls print function in message_printer.
My question is: How can I set a different message per thread and access it in message_printer?
message_printer:
import threading
threadLocal = threading.local()
def print_message():
name = getattr(threadLocal, 'name', None);
print name
return
main:
import threading
import message_printer
threadLocal = threading.local()
class Executor (threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
threadLocal.name = name
def run(self):
message_printer.print_message();
A = Executor("A");
A.start();
B = Executor("B");
B.start();
This just outputs None and None while I expect A and B. I also tried accessing threadLocal object inside the print_message function directly but doesn't work.
Note that this is just an example. In my application, the exact use case is for logging. Main launches a bunch of thread which call other modules. I want to have a different logger per thread (each thread should log to its own file) and each logger needs to be configured in Main. So I'm trying to instantiate logger per thread and set in thread local storage which can then be accessed in other modules.
What am I doing wrong? I'm following this question as an example Thread local storage in Python
The problem with your code, is that you are not assigning your name to the correct local() context. Your __init__() method is run in the main thread, before you start your A and B threads by calling .start().
Your first thread creation A = Executor("A"); will create a new thread A but update the local context of the main thread. Then, when you start A by calling A.start(); you will enter A:s context, with a separate local context. Here name is not defined and you end up with None as output. The same then happens for B.
In other words, to access the thread local variables you should be running the current thread, which you are when running .start() (which will call your .run() method), but not when creating the objects (running __init__()).
To get your current code working, you could store the data in each object (using self references) and then, when each thread is running, copy the content to the thread local context:
import threading
threadLocal = threading.local()
def print_message():
name = getattr(threadLocal, 'name', None);
print name
return
class Executor (threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
# Store name in object using self reference
self.name = name
def run(self):
# Here we copy from object to local context,
# since the thread is running
threadLocal.name = self.name
print_message();
A = Executor("A")
A.start()
B = Executor("B")
B.start()
Note, though, in this situation, it is somewhat of an overkill to use the thread local context, since we already store the separate data values in the different objects. To use it directly from the objects, would require a small rewrite of print_message() though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With