当前位置: 首页 > news >正文

(十八)Flask之threaing.local()对象

0、引子:

  • 如下是一段很基础的多线程代码:
from threading import Threaddemo = 0def task(arg):global demodemo = argprint(demo)for i in range(10):t = Thread(target=task, args=(i, ))t. start()

在这里插入图片描述

当程序运行时,可能会看到输出的顺序是混乱的,因为多个线程是并发执行的。这意味着它们可以同时访问和修改demo变量。因此,你可能会看到输出中的数字在不同的线程间交替出现。这就是多线程并发的典型行为。

简单分析,我上述给出的输出却是有序的?

短任务和快速启动: task函数的工作量很小,仅仅是一个赋值操作和一个打印操作。因此,当主线程在循环中迅速启动线程时,每个线程可能会在下一个线程启动之前完成其任务。

加个睡眠:

from threading import Thread
import timedemo = 0def task(arg):global demodemo = argtime.sleep(2)print(demo)for i in range(10):t = Thread(target=task, args=(i, ))t. start()

在这里插入图片描述

由于线程的启动和执行是并发的,并且demo是一个全局变量,多个线程可能在休眠结束后几乎同时打印它。加上time.sleep(2)的存在,这将使数据竞争更加明显,因此,打印的demo的值可能会与线程接收到的arg值不同。大部分情况下,输出可能会是连续的最后几个数字(如9、9、9…),但这并不是固定的,具体取决于线程调度和执行的实际顺序。

为了避免上述问题:就需要使用锁或其他同步机制来确保线程安全地访问共享资源。

而结合Flask,就来看其他的同步机制:如使用threading.local()对象!

一、threading.local()对象

threading.local()threading模块中是一个非常有用的工具,它提供了一个创建线程局部数据的方法。这意味着每个线程都有其独立的存储变量的实例,而不同线程之间不会相互干扰

当你创建一个threading.local()对象,每个线程可以为该对象赋予自己的属性值,而这些属性值对其他线程是不可见的。

比如:

from threading import Thread
from threading import local
import timedemo = local()def task(arg):demo.value = argtime.sleep(2)print(demo.value)for i in range(10):t = Thread(target=task, args=(i,))t.start()

在这里插入图片描述

回到Flask,Flask为什么需要threading.local()的功能?

回想一下前面讲的session部分,如果一下有很多人的请求进来,Flask处理可以开多个线程,但是每个人的请求都要单独开辟一块空间,去存储对应的数据,每个人的空间相互隔离开来,保证不出现紊乱。这样Flask就可以处理并发了!

仔细回想一下session部分:

当你访问例如flask.requestflask.session时,你实际上是在访问线程(或其他上下文)特定的变量。这意味着在同一个应用中,多个请求可以同时被处理,每个请求都有自己的requestsession对象,彼此之间完全隔离。

但是Flask没直接用threading.local(),而是自己实现了它!

下面就来研究下如何自己实现这个threading.local()的功能?

  • 提示:每个线程都有自己的唯一标识。
from threading import Thread
from threading import get_identdef task(arg):print(get_ident())for i in range(10):t = Thread(target=task, args=(i, ))t. start()

在这里插入图片描述

思路就是为每个线程维护一个字典:这个字典以线程id为key,值为value。形如下:

{6832: {va1: 0, va2: 2},8184: {va1: 6, va2: 5},16184: {va1: 0, va2: 11},
}
http://www.lryc.cn/news/268396.html

相关文章:

  • ffmpeg 硬件解码零拷贝unity 播放
  • 高德地图_公共交通路径规划API,获取两地点之间的驾车里程和时间
  • PyTorch深度学习实战(28)——对抗攻击(Adversarial Attack)
  • MariaDB单机多实例的配置方法
  • 加强->servlet->tomcat
  • Python初学者必须吃透的69个内置函数!
  • Day73力扣打卡
  • Android原生实现分段选择
  • 在 Unity 中获取 Object 对象的编辑器对象
  • idea自动注释
  • 阿里云 ACK 云上大规模 Kubernetes 集群高可靠性保障实战
  • 如何在无公网IP环境使用Windows远程桌面Ubuntu
  • Python——yolov8识别车牌2.0
  • Cookie的详解使用(创建,获取,销毁)
  • shell脚本自动化部署Zabbix4.2(修改脚本替换版本)
  • java SSM课程平台系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计
  • k8s二进制最终部署(网络 负载均衡和master高可用)
  • 【51单片机系列】DS1302时钟模块
  • 深入理解C语言中冒泡排序(优化)
  • 低代码选型注意事项
  • Caffeine--缓存组件
  • Centos7:Jenkins+gitlab+node项目启动(1)
  • starrocks集群fe/be节点进程守护脚本
  • 奇富科技跻身国际AI学术顶级会议ICASSP 2024,AI智能感知能力迈入新纪元
  • 如何在Android Termux中使用SFTP实现远程传输文件
  • 高频知识汇总 | 【操作系统】面试题汇总(万字长博通俗易懂)
  • 【前端框架】NPM概述及使用简介
  • C# LINQ
  • 云原生机器学习平台cube-studio开源项目及代码简要介绍
  • 大小端存储是什么鬼?