from threading import local

多个线程操作同一个变量,如果不加锁,会出现数据错乱问题,但是 读个线程同时操作 threading.local 对象 就不会出现数据错乱

作用: 线程变量,意思是threading.local中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量,threading.local为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变懒

不使用threading.local之前

由于多线程共享全局变量,所以一个线程拿到的全局变量的是未必是当时自己修改后的值,有可能在拿到全局变量之前其他线程也对该全局变量进行了修改,原因是线程的调度室友操作系统决定的

from threading import Thread, get_ident

import time

# 全局变量
num = 0 def task(arg):
global num
num += 1
time.sleep(1)
# get_ident()返回的是每一个线程的唯一标识
print('第%s条线程的值为:' % (get_ident()), num) for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
'''
由于每个线程只对全局变量做了一次修改
我们中间设置了1秒的延时
所以10个线程打印的全局变量的值都是最后修改的值,而并不是当时线程自己修改后的值。
'''

threading.local的基本使用

from threading import Thread, get_ident, local

import time

local_obj = local()

def task(arg):
# get_ident()返回的是每一个线程的唯一标识
print(get_ident())
# 在线程执行到此处时,为每一个线程开辟空间用来存储对象的值
local_obj.value = arg
time.sleep(1)
print('第%s条线程的值为:' % (get_ident()), local_obj.value) for i in range(10):
t = Thread(target=task, args=(i,))
t.start() '''
由于创建了threading.local对象
当为对象赋值属性的时候,会为每个线程开辟一块空间来存储对象的属性值,空间与空间之间数据是隔离的
这样最终打印的时候就是线程自己空间中保存的数据的值
'''

自定义local对象,基于函数

flask 的request,和session 都是全局的,但是我们在不同的视图函数中使用的 是针对于当前这次请求的对象,它的底层就是基于local写的

flask部署支持多进程线程架构,也支持协程架构,flask内部重写了local,让它支持线程和协程

import time

from threading import get_ident, Thread

# 构造一个全局字典
storage = {} def set(k, v):
# 获取当前字典
ident = get_ident()
if ident in storage:
# 如果当前线程id存在就修改id对应的值
storage[ident][k] = v
else:
# 如果不存在,就放进去,新增
storage[ident] = {k: v} def get(k):
ident = get_ident()
return storage[ident][k] def task(arg):
set('val', arg)
time.sleep(1)
print(get('val')) for i in range(10):
t = Thread(target=task, args=(i,))
t.start()

自定义local对象,基于面向对象(支持线程与协程)

import time

# 支持线程与协程
try:
# 如果用的是协程的,获取的就是协程的id号
from greenlet import getcurrent as get_ident
except Exception as e:
# 如果用的是线程的,那么获取到的就是线程的id号
from threading import get_ident from threading import Thread class CustomLocal(object):
"""
自定义local对象,基于面向对象
为每个线程(协程)开辟一块空间进行数据的存储
空间与空间之间是隔离的
""" def __init__(self):
# self.storage = {} # 执行此句代码的时候会先触发__setattr__方法
# 为了避免报错:RecursionError: maximum recursion depth exceeded while calling a Python object
# 需要先把storage创建出来,所以调用父类的__setattr__方法
# super(CustomLocal, self).__setattr__("storage", {})
object.__setattr__(self, 'storage', {}) # 父类调用类方法,类来调用变成普通函数,有几个值传入几个值,放入self里面去,后面用self.storage def __setattr__(self, key, value):
ident = get_ident()
if ident in self.storage:
self.storage[ident][key] = value
else:
self.storage[ident] = {key: value} # 执行此句的时候又会触发__setattr__方法,所有就进入了死循环 def __getattr__(self, item):
ident = get_ident() # 看是获取到的是线程的还是携程的id号
return self.storage[ident][item] local = CustomLocal() def task(arg):
local.var = arg
time.sleep(1)
print(local.var) for i in range(10):
t = Thread(target=task, args=(i,))
t.start()

threading.local的使用的更多相关文章

  1. 自定义threading.local

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

  2. threading.local学习

    多线程抢占问题 import time import threading obj = 5 def task(arg): global obj obj = arg time.sleep(1) print ...

  3. Threading.local

    在多线程环境下,每个线程都有自己的数据.一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其他线程,而全局变量的修改必须加锁. Threading.local可以创建 ...

  4. 网络编程 多线程/socketserver模块/ threading.local

    线程:进程中负责程序执行的执行单元. 多线程:在1个进程中存在多个线程. 进程只是用来把资源集中在一起,而线程才是cpu上的执行单位. 每个进程都会默认有一个控制线程也叫作主线程. 进程之间是竞争关系 ...

  5. 多线程局部变量之threading.local()用法

    假如,开了十个线程并且做同样的一件事,他们需要带着自己的数据进来,完成事情后带着自己的数据出去.如果是并发,同时进来,他们的数据就会混乱. 一般情况,我们加锁就可以了,一个人先进来,先加锁,另一个人过 ...

  6. python之threading.local

    简述: threading.local是全局变量但是它的值却在当前调用它的线程当中 作用: 在threading module中,有一个非常特别的类local.一旦在主线程实例化了一个local,它会 ...

  7. [Python 多线程] threading.local类 (六)

    在使用threading.local()之前,先了解一下局部变量和全局变量. 局部变量: import threading import time def worker(): x = 0 for i ...

  8. threading.local()方法;线程池

    一,threading.local() import time import threading v = threading.local() def func(arg): # 内部会为当前线程创建一个 ...

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

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

  10. 线程锁、threading.local(flask源码中用的到)、线程池、生产者消费者模型

    一.线程锁 线程安全,多线程操作时,内部会让所有线程排队处理.如:list/dict/Queue 线程不安全 + 人(锁) => 排队处理 1.RLock/Lock:一次放一个 a.创建10个线 ...

随机推荐

  1. odoo14、15里tree上加button【系统原生功能】

    odoo14.15里面tree视图已经添加了跟form一样的header标签,后面列表写button可以由此处扩展 系统案例:注意:按钮要选择数据后才出现 代码如下: <tree string= ...

  2. 转-Spring Data JPA中对象属性自动更新数据库

    摘要:使用Spring Data JPA获取的对象,其属性变更后自动更新数据库问题排查与解决方案. §问题描述   使用继承了JpaRepository的Dao从数据库中获取到某个对象,然后操作这个对 ...

  3. ubuntu2004 ROS1安装

    ubuntu初始环境配置ROS1 1.换源并更新数据库 ubuntu2004换源 # 备份原来的源并且另存 sudo cp -v /etc/apt/sources.list /etc/apt/sour ...

  4. 自签名证书工具cfssl详解

    概述 GitHub地址:https://github.com/cloudflare/cfssl 官方地址:https://pkg.cfssl.org CFSSL(CloudFlare's PKI an ...

  5. 详解鸿蒙Next仓颉开发语言中的动画

    大家上午好,今天来聊一聊仓颉开发语言中的动画开发. 仓颉中的动画通常有两种方式,分别是属性动画和显示动画,我们今天以下面的加载动画为例,使用显示动画和属性动画分别实现一下,看看他们有什么区别. 显示动 ...

  6. Springboot笔记<7>过滤器与拦截器

    过滤器 拦截器 过滤器 过滤器拦截的是URL Spring中自定义过滤器(Filter)一般只有一个方法,返回值是void,当请求到达web容器时,会探测当前请求地址是否配置有过滤器,有则调用该过滤器 ...

  7. MinHook 如何对.NET底层的 Win32函数 进行拦截(上)

    一:背景 1. 讲故事 在前面的系列中,我们聊过.NET外挂 harmony,他可以对.NET SDK方法进行拦截,这在.NET高级调试领域中非常重要,但这里也有一些遗憾,就是不能对SDK领域之外的函 ...

  8. LLM 上下文长度详细介绍

    1.概述 在<Token:大语言模型的"语言乐高",一切智能的基石>与<LLM 输出配置 (LLM output configuration)>这两篇博文中 ...

  9. cosbench工具使用方法

    一.Cosbench工具介绍 cosbench是intel开源的针对对象存储开发的测试工具 二.Cosbench安装 运行环境: 这里我们的系统是Centos7.6 依赖软件: JDK nmap-nc ...

  10. 【附源码】用Spring AI通杀所有MCP客户端,简直离谱!

    在上一章节中,我们讲解了MCP服务,并以Spring AI作为客户端和服务端进行示例说明.然而,当前市面上已经存在众多成熟的MCP客户端和服务端实现.那么,Spring AI在这些现有方案中的适配程度 ...