python语言线程标准库threading.local解读总结
作者:段明 发布时间:2023-12-22 18:18:07
标签:python,threading.local
本段源码可以学习的地方:
1. 考虑到效率问题,可以通过上下文的机制,在属性被访问的时候临时构建;
2. 可以重写一些魔术方法,比如 __new__ 方法,在调用 object.__new__(cls) 前后进行属性的一些小设置;
3. 在本库中使用的重写魔术方法,上下文这两种基础之上,我们可以想到函数装饰器,类装饰器,异常捕获,以及两种上下文的结构;
灵活运用这些手法,可以让我们在代码架构上更上一层,能够更加省时省力。
from weakref import ref # ref用在了构造大字典元素元组的第一个位置即 (ref(Thread), 线程字典)
from contextlib import contextmanager # 上下文管理,用来确保__dict__属性的存在
from threading import current_thread, RLock
__all__ = ["local"]
class _localimpl: # local()._local__impl = _localimpl() # local()实例的属性_local__impl就是这个类的实例
"""一个管理线程字典的类"""
__slots__ = 'key', 'dicts', 'localargs', 'locallock', '__weakref__' # _local__impl有这么多属性
def __init__(self):
# 这个self.key是用在线程对象的字典中的key
# self.key使用的一个字符串,这样既能运行的快,
# 但是通过'_threading_local._localimpl.' + str(id(self)也能保证不会冲突别的属性
self.key = '_threading_local._localimpl.' + str(id(self))
#
self.dicts = {} # 大字典
# 格式是: { id(线程1):(ref(Thread), 线程1自身的字典), id(线程2):(ref(Thread), 线程2自身的字典), ... }
def get_dict(self): # 从大字典中拿(ref(Thread), 线程字典), 然后取线程字典
thread = current_thread()
return self.dicts[id(thread)][1]
def create_dict(self): # 为当前线程创建一个线程字典,就是(ref(Thread), 线程字典)[1],即元组的第二部分
localdict = {}
key = self.key # key使用'_threading_local._localimpl.' + str(id(self)
thread = current_thread() # 当前线程
idt = id(thread) # 当前线程的id
def local_deleted(_, key=key): # 这个函数不看 pass
# When the localimpl is deleted, remove the thread attribute.
thread = wrthread()
if thread is not None:
del thread.__dict__[key]
def thread_deleted(_, idt=idt): # 这个函数不看 pass
# When the thread is deleted, remove the local dict.
# Note that this is suboptimal if the thread object gets
# caught in a reference loop. We would like to be called
# as soon as the OS-level thread ends instead.
local = wrlocal()
if local is not None:
dct = local.dicts.pop(idt)
wrlocal = ref(self, local_deleted)
wrthread = ref(thread, thread_deleted) # 大字典中每一个线程对应的元素的第一个位置: (ref(Thread), 小字典)
thread.__dict__[key] = wrlocal
self.dicts[idt] = wrthread, localdict # 在大字典中构造: id(thread) : (ref(Thread), 小字典)
return localdict
@contextmanager
def _patch(self):
impl = object.__getattribute__(self, '_local__impl') # 此时的self是local(), 拿local()._local__impl
try:
dct = impl.get_dict() # 然后从拿到的local()._local__impl调用线程字典管理类的local()._local__impl.get_dict()方法
# 从20行到22这个get_dict()方法的定义可以看出来,拿不到会报KeyError的
except KeyError: # 如果拿不到报 KeyError之后捕捉
dct = impl.create_dict() # 然后再通过线程字典管理类临时创建一个
args, kw = impl.localargs # 这个时候把拿到
self.__init__(*args, **kw)
with impl.locallock: # 通过上下文的方式上锁
object.__setattr__(self, '__dict__', dct) # 给local() 实例增加__dict__属性,这个属性指向大字典中value元组的第二个元素,即线程小字典
yield # 到目前为止,local()类的两个属性都构造完成
class local: # local类
__slots__ = '_local__impl', '__dict__' # local类有两个属性可以访问
def __new__(cls, *args, **kw):
if (args or kw) and (cls.__init__ is object.__init__): # pass不看
raise TypeError("Initialization arguments are not supported")
self = object.__new__(cls) # pass不看
impl = _localimpl() # _local_impl属性对应的是_localimpl类的实例
impl.localargs = (args, kw) # _local_impl属性即_localimpl类的实例 的 localargs属性是一个元组
impl.locallock = RLock() # pass 不看
object.__setattr__(self, '_local__impl', impl)
# 把_local__impl 增加给local(), 所以:local()._local__impl is ipml 即 _localimp()
# __slots__规定了local()有两个属性,这里已经设置了一个_local__impl;
# 第二个属性__dict__当我们以后在访问的时候使用上下文进行临时增加,比如第85行
impl.create_dict() # 就是local._local__impl.create_dict()
return self # 返回这个配置好_local__impl属性的local()实例
def __getattribute__(self, name): # 当我们取local()的属性时
with _patch(self): # 会通过上下文先把数据准备好
return object.__getattribute__(self, name) # 在准备好的数据中去拿要拿的属性name
def __setattr__(self, name, value):
if name == '__dict__': # 这个判断语句是控制local()实例的__dict__属性只能读不能被替换
raise AttributeError(
"%r object attribute '__dict__' is read-only"
% self.__class__.__name__)
with _patch(self): # 同理, 通过上下文先把__dict__构造好
return object.__setattr__(self, name, value) # 然后调用基类的方法设置属性
def __delattr__(self, name): # 删除属性,同理,和__setattr__手法相似
if name == '__dict__': # 这个判断语句是控制local()实例的__dict__属性只能读不能被替换
raise AttributeError(
"%r object attribute '__dict__' is read-only"
% self.__class__.__name__)
with _patch(self): # 同理, 通过上下文先把__dict__构造好
return object.__delattr__(self, name)
# 整体架构图:
'''
/ —— key 属性
/ —— dicts 属性, 格式{id(Thread):(ref(Thread), 线程小字典)}
———— : _local__impl属性 ---------- 是_local类的实例 |
/ —— 其他属性... |
/ /—————————————————————————————————————————————————————————————————————————————————/
创建一个local实例 /
\ /
\ /
———— : __dict__属性 -------- 对应的是_local__impl属性的dicts 中的线程小字典
'''
来源:https://www.cnblogs.com/duanming/p/11829354.html
0
投稿
猜你喜欢
- 我们都知道float:left和float:right,但是否想过float:center呢?居中浮动。。。<div id="
- 最近接触到Tencent的广告越来越多,户外广告牌和电视上都是,可以明显感觉到Tencent的扩张野心,以及对QQ品牌定位的重塑。摆脱低龄化
- 译者:AlphaImageLoader是一个让IE6正常显示PNG32时要用到的一个滤镜,但它在使用中也会产生一系列的问题,本文对使用Alp
- 模块:包含定义函数和变量的python文件,可以被别的程序引入。os模块是操作系统接口模块,提供了一些方便使用操作系统相关功能函数,这里介绍
- jQuery之父John Resig写过一篇《Sub-Pixel Problems in CSS》,一个50px宽的div中有4个float
- 在国内外大中型数据库管理系统中,把ORACLE作为数据库管理平台的用户比较多。RACLE 不论是数据库管理能力还是安全性都是无可非
- 《色彩解答》系列之一 色彩层次这次我们将深入进去了解一下众多色彩在一起之后所存在的“比例”关系。我们在使用色彩的时候不可能把所有的色彩都做得
- 前言以前在浏览文章时,看到过一个Android的加载效果,觉得挺好看的,于是自己就模仿了一个。下面话不多说,我们直接来看看详细的介绍吧。运行
- 别人复制你网站的文章时自动加上注释,这个功能你在很多网站应该都有体会过,当我们复制一段内容时,就自动在文章后面加上了网站的一些
- OpenCV:图片缩放和图像金字塔对图像进行缩放的最简单方法当然是调用resize函数啦!resize函数可以将源图像精确地转化为指定尺寸的
- 下面通过一段代码给大家介绍php参数过滤class mysafe{ public $logname; public $isshwomsg;
- 最近帮伙计做了一个从网页抓取股票信息并把相应信息存入MySQL中的程序。使用环境:Python 2.5 for WindowsMySQLdb
- 本文实例讲述了Python删除windows垃圾文件的方法。分享给大家供大家参考。具体如下:#coding:utf-8import os#f
- 1、fastcgi ,通过flup模块来支持,在nginx里对应的配置指令是 fastcgi_pass2、http,nginx使用proxy
- 在php中判断一个文件或目录是否存在,大家通常都会想到is_file和file_exists两个函数。但这两个函数再判断一个远程url文件是
- 用python实现21点小游戏,供大家参考,具体内容如下from random import shuffleimport randomimp
- 简介显示大量已经按类别(不是很多)排序的数据但没有类别分界线,用户很难找到所需要的类别。例如,数据库中只有9个类别(8个不同的类别和1个nu
- 一、问题描述通过调用MyQR模块来实现生成个人所需二维码。安装:pip install myqr二、代码实现1.普通二维码from MyQR
- CSS hack是指我们为了兼容各浏览器,而使用的特别的css定义技巧。这是国外摘来的一张CSS hack列表,显示了各浏览器对css ha
- 1、实现效果2、实现步骤模块导入import os,sys,timefrom PyQt5 import QtCore,QtWidgets,Q