python的_threading_local模块

本文介绍了Python中的_threading_local模块,详细解释了如何使用threading.local类管理线程局部数据,并通过实例展示了如何自定义此类及其特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天碰到跟_threading_local有关的问题,居然查不到太多信息,就自己翻译一下吧。

_threading_local
index
/usr/local/lib/python2.4/_threading_local.py
Module Docs

Thread-local 对象
(这个模块提供了threading.local类的Python版本,根据使用的Python版本的不同,可能会有更快的版本。你应该总是从threading里import local类。)
Thread-local对象提供对thread-local数据的管理。
如果你有需要对线程来讲是局部的数据,只需创建一个thread-local对象,像这样使用其属性:
  >>> mydata = local()
  >>> mydata.number = 42
  >>> mydata.number
  42
你也可以访问local对象的字典:
  >>> mydata.__dict__
  {'number': 42}
  >>> mydata.__dict__.setdefault('widgets', [])
  []
  >>> mydata.widgets
  []
关于thread-local对象最重要的就是它的数据对线程是局部的。如果我们像这样在不同的线程里访问该数据:
  >>> log = []
  >>> def f():
  ...     items = mydata.__dict__.items()
  ...     items.sort()
  ...     log.append(items)
  ...     mydata.number = 11
  ...     log.append(mydata.number)
  >>> import threading
  >>> thread = threading.Thread(target=f)
  >>> thread.start()
  >>> thread.join()
  >>> log
  [[], 11]
我们将得到不同的数据。进一步,在另一个线程里对数据的更改不会影响到当前线程里的数据:
  >>> mydata.number
  42
当然,你从一个local对象得到的值,包括__dict__属性,对任一个线程来说都是当前最新的。因此,你通常都不会想在线程之间为这些值,因为它们只属于被定义的那个线程。
你可以通过继承local类来自定义一个local对象:
  >>> class MyLocal(local):
  ...     number = 2
  ...     initialized = False
  ...     def __init__(self, **kw):
  ...         if self.initialized:
  ...             raise SystemError('__init__ called too many times')
  ...         self.initialized = True
  ...         self.__dict__.update(kw)
  ...     def squared(self):
  ...         return self.number ** 2
这样可以支持不同的值、方法和构造函数。注意如果你定义了__init__方法,它会在local对象在不同的线程被使用的时候被调用。这在需要初始化每个线程的字典的时候有用。
现在我们来创建一个local对象:
  >>> mydata = MyLocal(color='red')
我们有了不同的number:
  >>> mydata.number
  2
一个初始化了的color:
  >>> mydata.color
  'red'
  >>> del mydata.color
还有一个处理数据的方法:
  >>> mydata.squared()
  4
跟以前一样,我们可以在另一个线程里访问数据:
  >>> log = []
  >>> thread = threading.Thread(target=f)
  >>> thread.start()
  >>> thread.join()
  >>> log
  [[('color', 'red'), ('initialized', True)], 11]
当前线程的数据不受影响:
  >>> mydata.number
  2
  >>> mydata.color
  Traceback (most recent call last):
  ...
  AttributeError: 'MyLocal' object has no attribute 'color'
子类可以定义slot,但是这不是线程局部的。它们在线程之间是共享的:
  >>> class MyLocal(local):
  ...     __slots__ = 'number'
  >>> mydata = MyLocal()
  >>> mydata.number = 42
  >>> mydata.color = 'red'
因此,另一个线程:
  >>> thread = threading.Thread(target=f)
  >>> thread.start()
  >>> thread.join()
会影响到当前线程:
  >>> mydata.number
  11
>>> del mydata

### Python 中 `threading` 模块的使用教程 #### 创建和启动线程 可以通过继承 `Thread` 类或传递目标函数的方式来创建新线程。 对于通过继承的方式实现多线程: ```python import threading import time class WorkerThread(threading.Thread): def run(self): print('Start working') time.sleep(1) print('End work') worker = WorkerThread() worker.start() worker.join() # 等待直到该线程终止[^4] ``` 另一种更简单的方法是直接指定一个可调用对象作为参数来初始化 `Thread` 实例,这通常是一个普通的函数: ```python def task(): print('Start working') time.sleep(1) print('End work') task_thread = threading.Thread(target=task) task_thread.start() task_thread.join() # 阻塞当前上下文环境的主线程,直到调用了 join 方法的那个线程执行结束为止[^2] ``` #### 守护线程 vs. 非守护线程 默认情况下,所有线程都是非守护线程。这意味着程序会等待这些线程完成之后才会退出。如果设置为守护线程,则当仅剩余守护线程时,整个应用程序将会立即关闭而不会等待它们完成工作。 要将线程设为守护模式,在创建后但在启动前调用 `.setDaemon(True)` 或者是在构造器中传入 daemon 参数[^1]: ```python daemon_thread = threading.Thread(target=some_function, daemon=True) daemon_thread.start() # 或者也可以这样写 another_daemon = threading.Thread(target=some_other_function, args=(arg,), kwargs={'kw': 'value'}, daemon=True) another_daemon.start() ``` #### 同步原语——锁机制 为了防止多个线程同时访问共享资源造成数据竞争条件,可以利用同步工具如互斥锁 (`Lock`) 来保护临界区代码片段。 下面的例子展示了如何安全地更新全局计数器变量而不发生竞态错误: ```python counter = 0 lock = threading.Lock() def update_counter(): global counter with lock: # 自动获取并释放锁 local_copy = counter local_copy += 1 time.sleep(0.1) # 模拟耗时操作 counter = local_copy threads = [threading.Thread(target=update_counter) for _ in range(10)] for t in threads: t.start() for t in threads: t.join() print(f'Final Counter Value: {counter}') # 应该总是打印 "Final Counter Value: 10"[^3] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值