threading.local()使用与原理剖析

前言

  还是第一次摘出某个方法来专门写一篇随笔,哈哈哈。

  为什么要写这个方法呢?因为它确实太重要了,包括后期的Flask框架源码中都有它的影子。

  那么我们就来瞄一眼这个东西是啥吧。

作用

  在Python官方中文文档中(Python3.8.4),对它的介绍其实并不是很详细

  其实他的功能非常简单,如下:

  在一个全局的容器中可以存放一些线程独有的数据,这些数据应是某一线程私有的,是除了本线程外的其他线程访问不到的。

  举个例子,例如你用迅雷下载的时候每条线程的下载进度不一样,我们需要将下载进度这个数据存储起来,怎么存储?自己创建一个具有线程安全性的列表或字典?那太麻烦了,请记住一点,数据怎么存不重要,关键是要方便取,取的快,取的准才是王道,所以直接用thrading.local()方法即可。

  我来画一张吧,灵魂画师上线,能用图描述绝对不打字。

基本使用

  threading.local():可以实例化出一个寄存柜,这个寄存柜是全局化的

  寄存柜对象.你想放的东西名字 = 东西:你可以在线程中这样放入一个独有的物件

  寄存柜对象.你放过的东西的名字:这样,你就可以将你存放进的东西拿出来。注意,只有你才能拿出来,其他人拿不了。

import threading
import time def operate(name):
"""操作"""
print("三个月后,{0}忽然想起了自己有件东西放在柜子里,决定取出来".format(name))
print("最后他从自己的柜子里取出来了:",Locker.article) def people(article):
name = threading.current_thread().getName() # 获取线程名
Locker.article = article # 这就表示将私有的的一件物品放在了寄存柜里
print("{0}将{1}放在了寄存柜里...".format(name,article))
time.sleep(3) # 过了三个月,这期间发生了很多事
operate(name) if __name__ == '__main__':
Locker = threading.local() # 好了寄存柜放在全局了
t1 = threading.Thread(target=people,args=("一封情书",),name="小王")
t2 = threading.Thread(target=people,args=("一双臭袜子",),name="小李")
t1.start()
t2.start()
t1.join()
t2.join() # ==== 执行结果 ==== """
小王将一封情书放在了寄存柜里...
小李将一双臭袜子放在了寄存柜里...
三个月后,小王忽然想起了自己有件东西放在柜子里,决定取出来
最后他从自己的柜子里取出来了: 一封情书
三个月后,小李忽然想起了自己有件东西放在柜子里,决定取出来
最后他从自己的柜子里取出来了: 一双臭袜子
"""

原理分析

  我们可以自己做一个全局字典,来实现与这个类似的功能,但是使用起来肯定不太方便(它实际上本质就是字典嵌套进行存储的):

import threading
import time Locker = {} # 好了寄存柜放在全局了
"""
{
线程id:{"article":"存放的具体物品"},
线程id:{"article":"存放的具体物品"},
线程id:{"article":"存放的具体物品"},
}
""" def operate(name):
"""操作"""
print("三个月后,{0}忽然想起了自己有件东西放在柜子里,决定取出来".format(name))
ident = threading.get_ident() # 获取线程ID
print("最后他从自己的柜子里取出来了:",Locker[ident]["article"]) def people(article):
name = threading.current_thread().getName() # 获取线程名
ident = threading.get_ident() # 获取线程ID
Locker[ident] = {} # 创建了一个寄存柜的小格子
Locker[ident]["article"] = article # 这就表示将私有的的一件物品放在了寄存柜里
print("{0}将{1}放在了寄存柜里...".format(name,article))
time.sleep(3) # 过了三个月,这期间发生了很多事
operate(name) if __name__ == '__main__': t1 = threading.Thread(target=people,args=("一封情书",),name="小王")
t2 = threading.Thread(target=people,args=("一双臭袜子",),name="小李")
t1.start()
t2.start()
t1.join()
t2.join() # ==== 执行结果 ==== """
小王将一封情书放在了寄存柜里...
小李将一双臭袜子放在了寄存柜里...
三个月后,小李忽然想起了自己有件东西放在柜子里,决定取出来
最后他从自己的柜子里取出来了: 一双臭袜子
三个月后,小王忽然想起了自己有件东西放在柜子里,决定取出来
最后他从自己的柜子里取出来了: 一封情书
"""

尝试自己做出一个寄存柜

  这样做是不是太麻烦了?我们可以自定义一个类,让它变得更加简单,如同原本的使用方法一样。其实下面代码中采取的方法也是threading.local()所采取的方法。

import threading
import time class MyLocker(object):
cabinet = {} # 柜子
"""
{
线程id:{"article":"存放的具体物品"},
线程id:{"article":"存放的具体物品"},
线程id:{"article":"存放的具体物品"},
}
""" def __getattr__(self, item):
"""当访问属性不存在时触发"""
ident = threading.get_ident()
return MyLocker.cabinet[ident][item] def __setattr__(self, key, value):
"""试图用 . 去设置属性时触发"""
ident = threading.get_ident()
if ident in MyLocker.cabinet: # 如果在柜子里这重新赋值
MyLocker.cabinet[ident][key] = value
else:
MyLocker.cabinet[ident] = {key: value} # 如果不在则做一个小格子,并且把物件存放进来 def operate(name):
"""操作"""
print("三个月后,{0}忽然想起了自己有件东西放在柜子里,决定取出来".format(name))
print("最后他从自己的柜子里取出来了:", Locker.article) def people(article):
name = threading.current_thread().getName() # 获取线程名
Locker.article = article # 这就表示将私有的的一件物品放在了寄存柜里
print("{0}将{1}放在了寄存柜里...".format(name, article))
time.sleep(3) # 过了三个月,这期间发生了很多事
operate(name) if __name__ == '__main__':
Locker = MyLocker() # 好了寄存柜放在全局了
t1 = threading.Thread(target=people, args=("一封情书",), name="小王")
t2 = threading.Thread(target=people, args=("一双臭袜子",), name="小李")
t1.start()
t2.start()
t1.join()
t2.join() # ==== 执行结果 ==== """
小王将一封情书放在了寄存柜里...
小李将一双臭袜子放在了寄存柜里...
三个月后,小王忽然想起了自己有件东西放在柜子里,决定取出来
最后他从自己的柜子里取出来了: 一封情书
三个月后,小李忽然想起了自己有件东西放在柜子里,决定取出来
最后他从自己的柜子里取出来了: 一双臭袜子
"""

threading.local()使用与原理剖析的更多相关文章

  1. threading.local作用及原理

    先看下应用: import threading from threading import local import time obj = local() def task(i): obj.xxxxx ...

  2. flask上下文管理相关 - threading.local 以及原理剖析

    threading.local 面向对象相关: setattr/getattr class Foo(object): pass obj = Foo() obj.x1 = 123 # object.__ ...

  3. 多线程threading.local的作用及原理?

    1.示例代码 import time import threading v = threading.local() def func(arg): # 内部会为当前线程创建一个空间用于存储:phone= ...

  4. 03 flask源码剖析之threading.local和高级

    03 threading.local和高级 目录 03 threading.local和高级 1.python之threading.local 2. 线程唯一标识 3. 自定义threading.lo ...

  5. ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)

    ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...

  6. 【Xamarin挖墙脚系列:Xamarin.IOS机制原理剖析】

    原文:[Xamarin挖墙脚系列:Xamarin.IOS机制原理剖析] [注意:]团队里总是有人反映卸载Xamarin,清理不完全.之前写过如何完全卸载清理剩余的文件.今天写了Windows下的批命令 ...

  7. NameNode和SecondaryNameNode工作原理剖析

    NameNode和SecondaryNameNode工作原理剖析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.NameNode中的元数据是存储在那里的? 1>.首先,我 ...

  8. 开源 serverless 产品原理剖析 - Kubeless

    背景 Serverless 架构的出现让开发者不用过多地考虑传统的服务器采购.硬件运维.网络拓扑.资源扩容等问题,可以将更多的精力放在业务的拓展和创新上. 随着 serverless 概念的深入人心, ...

  9. 自定义threading.local

    1.threading相关. # Author:Jesi # Time : 2018/12/28 14:21 import threading import time from threading i ...

随机推荐

  1. Java实现蓝桥杯历届试题回文数字

    历届试题 回文数字 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 观察数字:12321,123321 都有一个共同的特征,无论从左到右读还是从右向左读,都是相同的.这样的数字叫做: ...

  2. Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素 - 允许重复

    381. O(1) 时间插入.删除和获取随机元素 - 允许重复 设计一个支持在平均 时间复杂度 O(1) 下, 执行以下操作的数据结构. 注意: 允许出现重复元素. insert(val):向集合中插 ...

  3. Java实现 LeetCode 82 删除排序链表中的重复元素 II(二)

    82. 删除排序链表中的重复元素 II 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 示例 1: 输入: 1->2->3->3->4- ...

  4. java实现识别复制串

    ** 识别复制串** 代码的目标:判断一个串是否为某个基本串的简单复制构成的. 例如: abcabcabc,它由"abc"复制3次构成,则程序输出:abc aa 由"a& ...

  5. Linux 最大有效权限与删除ACL

    最大有效权限mask mask是用来指定最大有效权限的.如果给用户赋予了acl权限,则需要与mask权限”相与“才能得到用户的真正权限 setfacl -m m:rx 文件名,指定最大有效权限.例如: ...

  6. 如何快速的找到好玩的旅游景点信息?Python爬虫帮你轻松解决

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 喜欢的朋友欢迎关注小编 当我们出去旅游时,会看这个地方有哪些旅游景点,景点 ...

  7. 【Spring注解驱动开发】使用@Scope注解设置组件的作用域

    写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...

  8. Hbase的基本架构以及对应的读写流程

    一.HBase简介 1,定义: HBase 是一种分布式.可扩展.支持海量数据存储的 NoSQL 数据库. 2,HBase的架构图: 架构角色: 1)Master Master是所有Region Se ...

  9. pytorch入门2.2构建回归模型初体验(开始训练)

    pytorch入门2.x构建回归模型系列: pytorch入门2.0构建回归模型初体验(数据生成) pytorch入门2.1构建回归模型初体验(模型构建) pytorch入门2.2构建回归模型初体验( ...

  10. Windows环境下PHP安装pthreads多线程扩展

    一.判断PHP是ts还是nts版 通过phpinfo(); 查看其中的 Thread Safety 项,这个项目就是查看是否是线程安全,如果是:enabled,一般来说应该是ts版,否则是nts版. ...