首页 > 其他分享 >threading.local的使用

threading.local的使用

时间:2022-12-14 22:11:39浏览次数:35  
标签:__ ident get threading 线程 使用 local

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()

标签:__,ident,get,threading,线程,使用,local
From: https://www.cnblogs.com/zxr1002/p/16983779.html

相关文章

  • 在idea中使用git
    一、在idea中配置git二、获取git仓库本地初始化仓库选择项目目录作为仓库的目录从远程仓库克隆(更多使用)方式一:方式二:三、本地仓库操作说明:在创建仓库时也可......
  • k8s的污点、容忍度以及亲和性的使用
    亲和性node节点亲和性调度nodeAffinitynode亲和性是决定pod与节点的关系$kubectlexplainpods.spec.affinityKIND:PodVERSION:v1RESOURCE:affinity<Obj......
  • 【阿里云短信】开通使用
    进入短信控制台百度搜索:阿里大鱼访问首页 选择短信服务  用户登录 登录成功,进入管理控制台 开通服务 业务激活 激活成功,进行概览 再次进入短信服务 使用签名管理发......
  • HTML表单的使用
    1.form表单:属性:method:提交方式(get显示提交,post隐性提交)action:数据提交地址enctype:表单编码属性例:<formmethod="get"action="#"enctype="multipart/form-data......
  • win10更新后使用ie浏览器自动跳转edge的解决方法
    win10更新后使用ie浏览器自动跳转edge的解决方法①在系统的搜索框中搜索internet选项②打开界面中,选择高级的栏位③然后在红框的地方找到启用第三方浏览器扩展,去掉勾......
  • 【C语言】数组指针、&数组名和数组名、数组是首元素地址(两特殊情况)、数组指针访问二
    ......
  • 欢迎使用CSDN-markdown编辑器
    欢迎使用Markdown编辑器写博客本Markdown编辑器使用​​StackEdit​​修改而来,用它写博客,将会带来全新的体验哦:Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片......
  • Alpine介绍与apk的基本使用
    前言Alpine是一个面向安全的轻量级的Linux发行版,相比与CentOS,ubuntu体积小很多,大约只有5M左右,由于体积小的原因,在很多场景下都会使用它来按需制作一些轻量级镜像,虽然体......
  • Linux 控制CPU资源使用
    限制CPU的方式有以下几种:1、taskset2、cpulimit一、taskset-p,--pid对一个已存在的pid进行操作-c,--cpu-list限定进程到指定的cpu上,可以指定多个,以逗号分隔,......
  • Qt平台下使用QJson 使用
    前言在Qt开发环境下使用Json的解析和输出当然要使用QJson来完成。QJson解析JSON主要使用的类如下#include<QJsonDocument>#include<QJsonObject>#include<QJsonArray>......