|
import threading |
|
from contextlib import contextmanager |
|
from concurrent.futures import ThreadPoolExecutor, as_completed |
|
import copy |
|
|
|
class Settings: |
|
def __init__(self): |
|
|
|
self._lock = threading.Lock() |
|
|
|
|
|
self._parent_configs = {} |
|
|
|
|
|
self._local = threading.local() |
|
|
|
def _get_current_config(self): |
|
return self._local.config_stack[-1] if hasattr(self._local, 'config_stack') and self._local.config_stack else {} |
|
|
|
def initialize_for_thread(self, parent_tid): |
|
"""Initialize thread-local data for a new thread using its parent's config.""" |
|
with self._lock: |
|
parent_config = self._parent_configs.get(parent_tid) |
|
if parent_config: |
|
self._local.config_stack = [copy.deepcopy(parent_config)] |
|
else: |
|
self._local.config_stack = [{}] |
|
|
|
@contextmanager |
|
def context(self, **kwargs): |
|
current_config = copy.deepcopy(self._get_current_config()) |
|
current_config.update(kwargs) |
|
|
|
if not hasattr(self._local, 'config_stack'): |
|
self._local.config_stack = [] |
|
|
|
self._local.config_stack.append(current_config) |
|
|
|
|
|
with self._lock: |
|
self._parent_configs[threading.get_ident()] = copy.deepcopy(current_config) |
|
|
|
try: |
|
yield |
|
finally: |
|
self._local.config_stack.pop() |
|
|
|
|
|
with self._lock: |
|
self._parent_configs.pop(threading.get_ident(), None) |
|
|
|
|
|
dsp_settings = Settings() |
|
|
|
|
|
|
|
def thread_wrapper(program, parent_tid, *args, **kwargs): |
|
dsp_settings.initialize_for_thread(parent_tid) |
|
return program(*args, **kwargs) |
|
|
|
|
|
|
|
def sample_program(arg): |
|
print(f"Thread {threading.get_ident()} with arg={arg} has config: {dsp_settings._get_current_config()}") |
|
|
|
|
|
def main(): |
|
parent_tid = threading.get_ident() |
|
|
|
with dsp_settings.context(a=10, b=20): |
|
with ThreadPoolExecutor(max_workers=2) as executor: |
|
futures = {executor.submit(thread_wrapper, sample_program, parent_tid, arg) for arg in range(3)} |
|
|
|
for future in as_completed(futures): |
|
res = future.result() |
|
|
|
print(f"Main thread {parent_tid} config after threads: {dsp_settings._get_current_config()}") |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|