Python | threading

Python | threading

1. 简介

Python的threading模块是用于创建和管理线程的标准库。线程是在同一进程中执行的多个执行路径,使程序可以同时执行多个任务。

threading模块提供了Thread类,通过创建Thread对象,可以轻松地在Python中启动和管理线程。

2. 多线程

2.1. 继承方式

import threading
import timeclass MyThread(threading.Thread):def run(self):print('start working')time.sleep(1)print('end work')my_thread = MyThread()
my_thread.start()
my_thread.join()

2.2. 回调方式

import threading
import timedef run():print('start working')time.sleep(1)print('end work')my_thread = threading.Thread(target=run)
my_thread.start()
my_thread.join()

3. threading.Lock 锁

import threadingclass Fruits:list: [str] = []lock: threading.Lock = threading.Lock()def add(self, fruit: str):with self.lock:index = self.__get_index(fruit)if index == -1:# 存在更新self.list.append(fruit)def update(self, old: str, new: str):with self.lock:index = self.__get_index(old)if index != -1:# 存在更新self.list[index] = newdef get_index(self, fruit: str) -> int:with self.lock:return self.__get_index(fruit)def __get_index(self, fruit: str) -> int:for index in range(len(self.list)):if self.list[index] == fruit:return indexreturn -1fruits = Fruits()
fruits.add('Banana')
fruits.update('Banana', 'Apple')
print(fruits.get_index('Banana'))
print(fruits.get_index('Apple'))

4. threading.RLock 重入锁

此处RLock并非读写锁,表示重入锁,同一个线程可以多次获取锁。
对比Lock的示例代码,RLock经常使用在一个API既需要内部使用,又需要开放外部访问保证线程安全时特别有用。

import threadingclass Fruits:list: [str] = []lock: threading.RLock = threading.RLock()def add(self, fruit: str):with self.lock:index = self.get_index(fruit)if index == -1:# 存在更新self.list.append(fruit)def update(self, old: str, new: str):with self.lock:index = self.get_index(old)if index != -1:# 存在更新self.list[index] = newdef get_index(self, fruit: str) -> int:with self.lock:for index in range(len(self.list)):if self.list[index] == fruit:return indexreturn -1fruits = Fruits()
fruits.add('Banana')
fruits.update('Banana', 'Apple')
print(fruits.get_index('Banana'))
print(fruits.get_index('Apple'))

5. threading.Timer 非周期性定时器

import threading
import datetimedef work():print(f'hello {datetime.datetime.now()}')timer = threading.Timer(2, work)
# 2秒过后调用work
timer.start()
# timer.cancel()

6. threading.Semaphore 信号量

常用方法

semaphore = threading.Semaphore(value=2)  # 总资源数量2
semaphore.acquire()  # 请求资源
semaphore.release(n=1)  # 释放资源

使用示例:中间件

import threading# 令牌桶,网站同时只允许1000人访问
tokenBucket = threading.Semaphore(value=1000)class HTTPRequest:passdef abort(req: HTTPRequest):passdef next_step(req: HTTPRequest):pass# 模拟HTTP中间件
def middleware(req: HTTPRequest):b: bool = Falsetry:# 获取令牌b = tokenBucket.acquire(blocking=False)if not b:# 失败,中止访问abort(req)# 成功,继续下一步next_step(req)finally:if b:# 归还令牌tokenBucket.release()

7. threading.BoundedSemaphore 边界信号量

threading.Semaphore不同的是,资源数量被限制不能超过初始资源数量。

import threadingsemaphore = threading.BoundedSemaphore(value=10)
semaphore.acquire()
semaphore.release()
# Exception: Semaphore released too many times
semaphore.release()

8. threading.Barrier 栅栏

threading.Barrier 是 Python 中 threading 模块中的同步原语,它用于在多个线程中进行同步,确保这些线程在达到指定的屏障点之前都会被阻塞,然后在所有线程都到达屏障点后同时继续执行。

threading.Barrier 适用于需要所有线程到达某个点之后再继续执行的场景,比如等待所有线程完成一定阶段的工作后再进行下一阶段的操作。

threading.Barrier 的常用方法是:

  1. __init__(parties, action=None): 创建一个 Barrier 对象。parties 参数指定需要等待的线程数量,当有 parties 个线程都调用 wait() 方法后,所有线程将同时释放并继续执行。可选的 action 参数可以指定一个回调函数,当所有线程释放后,此回调函数将在释放线程中的一个线程中执行。
  2. wait(timeout=None): 阻塞线程,直到所有参与线程都调用了 wait() 方法并达到屏障点。可选的 timeout 参数用于设置等待的超时时间,如果超过此时间,线程将被解除阻塞。

下面是 threading.Barrier 的一个简单示例:

import threadingdef worker(barrier, name):print(f"{name}: 执行任务前")barrier.wait()print(f"{name}: 执行任务后")# 创建 Barrier 对象,需要等待3个线程
barrier = threading.Barrier(3)# 创建3个工作线程
thread1 = threading.Thread(target=worker, args=(barrier, "线程1"))
thread2 = threading.Thread(target=worker, args=(barrier, "线程2"))
thread3 = threading.Thread(target=worker, args=(barrier, "线程3"))# 启动工作线程
thread1.start()
thread2.start()
thread3.start()# 等待所有线程完成
thread1.join()
thread2.join()
thread3.join()print("所有线程已完成。")

9. threading.Event 事件

threading.Event 是 Python 中 threading 模块中的同步原语,它允许线程等待直到被其他线程设置为真的事件。它通常用于协调多个线程的活动,并促进它们之间的通信。

threading.Event 的主要作用是为线程提供一个简单的机制,使它们能够在特定条件满足之前暂停执行。与 threading.Event 相关的两个主要方法是:

  1. set(): 设置事件为真。正在使用 wait() 方法等待事件的线程将被释放,可以继续执行。

  2. clear(): 重置事件为假。随后调用 wait() 的线程将被阻塞,直到再次使用 set() 方法设置事件。

除了这两个方法之外,还有 wait(timeout=None) 方法。当线程调用 wait() 时,它将被阻塞,直到事件被设置或达到可选的 timeout 参数为止。如果提供了超时,并且事件在指定的时间内没有被设置,线程将继续执行,而不考虑事件状态。

下面是 threading.Event 的一个基本示例:

import random
import threading
import timeevent = threading.Event()
runners = ['runner1', 'runner2', 'runner3']
threads = []def start(name: str):print(f'{name} 准备就绪')event.wait()print(f'{name} 起跑')time.sleep(random.randint(1, 3))print(f'{name} 到达终点')# 准备
for runner in runners:t = threading.Thread(target=start, args=(runner,))t.start()threads.append(t)# 让所有跑步者都进入等待,此处处理并不优雅,但这里主要目的是为了演示event。
time.sleep(1)
# 发令
event.set()for t in threads:t.join()

10. threading.Condition

threading.Condition 是 Python 中 threading 模块中的同步原语,它用于在多个线程之间进行复杂的协调和通信。它提供了一个通用的条件变量,允许线程等待某个条件为真,或者在满足条件时通知其他等待的线程。

threading.Condition 主要用途是在多线程环境下实现线程间的协作,特别是用于生产者-消费者模式和线程间的消息传递。通过使用 threading.Condition,我们可以让一个线程等待直到满足特定条件,然后另一个线程通知条件已经满足,从而实现线程间的同步。

threading.Condition 的常用方法有:

  1. __init__(lock=None): 创建一个 Condition 对象。可选的 lock 参数指定一个锁对象,用于在内部同步条件的访问。如果不提供锁对象,Condition 会自动创建一个默认的锁对象。
  2. acquire(): 获取底层关联的锁,用于保护共享资源或条件。
  3. release(): 释放底层关联的锁。
  4. wait(timeout=None): 等待条件为真。调用此方法将释放关联的锁并阻塞线程,直到另一个线程调用 notify()notify_all() 方法通知条件为真或超时。
  5. notify(n=1): 唤醒等待此条件的一个线程。默认情况下,唤醒一个等待的线程,如果指定 n 参数,将唤醒 n 个等待的线程。
  6. notify_all(): 唤醒所有等待此条件的线程。

下面是一个使用 threading.Condition 的简单示例:

import threadingcar_condition = threading.Condition()
toll_collector_semaphore = threading.Semaphore(value=0)def waiting_for_release(name: str):print(f'{name} 到达,等待放行')# 记录当前有等待放行toll_collector_semaphore.release()with car_condition:car_condition.wait()print(f'{name} 放行')def toll_collector():while True:toll_collector_semaphore.acquire()with car_condition:# 放行一辆car_condition.notify()cars = ['A', 'B', 'C', 'D']# 启动收费员
threading.Thread(target=toll_collector).start()for car in cars:threading.Thread(target=waiting_for_release, args=(car,)).start()

11. 参考

  • python 实现线程之间的通信
  • Python 多线程编程-07-threading 模块 - Barrier

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/21997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hum Brain Mapp:用于功能连接体指纹识别和认知状态解码的高精度机器学习技术

摘要 人脑是一个复杂的网络,由功能和解剖上相互连接的脑区组成。越来越多的研究表明,对脑网络的实证估计可能有助于发现疾病和认知状态的生物标志物。然而,实现这一目标的先决条件是脑网络还必须是个体的可靠标记。在这里,本研究…

Docker入门之运行Nginx案例

运行镜像 如果你直接安装会比较慢, 建议参照附录内容配置镜像之后再执行 # 执行命令过程一:下载容器镜像 docker run -d nginx:latest 命令解释 docker run 启动一个容器 -d 把容器镜像中需要执行的命令以daemon(守护进程)的方式运行 nginx…

性能优化-react路由懒加载和组件懒加载

背景 随着项目越来越大,打包后的包体积也越来越大,严重影响了首屏加载速度,需要对路由和组件做懒加载处理 主要用到了react中的lazy和Suspense。 废话不多说,直接上干货 路由懒加载 核心代码 import React, { lazy, Suspens…

GPS/北斗RTK差分定位系统的原理以及应用领域

导语:现代定位技术在国内外的发展与应用越来越广泛,其中GPS和北斗是两大被广泛使用的全球卫星定位系统。本文将介绍GPS/北斗RTK差分定位系统的原理以及其在各个领域的应用。 一、GPS/北斗RTK差分定位系统的原理 GPS/北斗RTK差分定位系统,即全…

【TypeScript】安装的坑!

TypeScript安装 安装TypeScript安装时候可能报错这样开头的数据(无法枚举容器中的对象)——原因:没权限先解决没权限的问题如果发现无法修改-高级-修改继续安装想使用tsc-发现,tsc不能用解决方法:配置环境变量最后的最…

便捷省心的手机直播影视工具,畅享轻松电视娱乐时光

便捷省心的手机直播影视工具,畅享轻松电视娱乐时光 在快节奏的现代生活中,我们常常渴望能够以简单、省心的方式消遣自己,享受高品质的电视娱乐。幸运的是,随着技术的进步,便捷省心的手机直播影视工具应运而生。这些工…

Adaptive autosar 都有哪些模块?各有什么功能?

Adaptive autosar是一种用于高性能计算ECU的软件平台,它支持自适应应用程序的开发和运行。它由两部分组成:基础(Foundation)和服务(Service)。基础包括了操作系统接口、执行管理、网络管理、识别访问管理、加密、更新和配置管理等功能。服务包括了通信管理、RESTful、时间…

【目标检测论文解读复现NO.33】改进YOLOv5的新能源电池集流盘缺陷检测方法

前言 此前出了目标改进算法专栏,但是对于应用于什么场景,需要什么改进方法对应与自己的应用场景有效果,并且多少改进点能发什么水平的文章,为解决大家的困惑,此系列文章旨在给大家解读最新目标检测算法论文&#xff0c…

Kubernetes v1.20 二进制部署

架构 k8s集群master01:192.168.80.101 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02:192.168.80.102 k8s集群node01:192.168.80.103 kubelet kube-proxy docker k8s集群node02:192.168.80…

Vue3文字实现左右和上下滚动

可自定义设置以下属性&#xff1a; 滚动文字数组&#xff08;sliderText&#xff09;&#xff0c;类型&#xff1a;Array<{title: string, link?: string}>&#xff0c;必传&#xff0c;默认[] 滚动区域宽度&#xff08;width&#xff09;&#xff0c;类型&#xff1a…

git拉取代码时出现Filename too long错误Git处理长路径

背景 git拉取代码时出现Filename too long错误 现象 如下&#xff1a; $ git checkout . error: unable to create file boot-starters/permission-access-security-service-boot-starter/src/main/java/cn/gzs***/basic/system/platform/starter/permission/access/resourc…

后端整理(MySql)

1 事务 1.1 事务ACID原则 原子性&#xff08;Atomicity&#xff09; 事务的原子性指的是事务的操作&#xff0c;要么全部成功&#xff0c;要么全部失败回滚 一致性&#xff08;Consistency&#xff09; 事务的一致性是指事务必须使数据库从一个一致状态转变成另一个一致性…

机器学习05-数据准备(利用 scikit-learn基于Pima Indian数据集作数据预处理)

机器学习的数据准备是指在将数据用于机器学习算法之前&#xff0c;对原始数据进行预处理、清洗和转换的过程。数据准备是机器学习中非常重要的一步&#xff0c;它直接影响了模型的性能和预测结果的准确性 以下是机器学习数据准备的一些常见步骤&#xff1a; 数据收集&#xff…

使用kubeadm快速部署一个k8s集群

Kubernetes概述 使用kubeadm快速部署一个k8s集群 Kubernetes高可用集群二进制部署&#xff08;一&#xff09;主机准备和负载均衡器安装 Kubernetes高可用集群二进制部署&#xff08;二&#xff09;ETCD集群部署 Kubernetes高可用集群二进制部署&#xff08;三&#xff09;部署…

JVM之垃圾回收器

1.如何判断对象可以回收 1.1 引用计数法 什么是引用计数器法 在对象中添加一个引用计数器&#xff0c;每当有一个地方引用它时&#xff0c;计数器值就加一&#xff1b;当引用失效时&#xff0c;计数器值就减一&#xff1b;任何时刻计数器为零的对象就是不可能再被使用的。 …

【C语言学习】整数范围、整数越界、无符号数

1.整数范围 对于一个字节&#xff08;8位&#xff09;&#xff0c;可以表达的范围是00000000 ~ 11111111 其中00000000 ——> 0 11111111 ~ 10000000 ——> -1 ~ -128&#xff08;从大到小&#xff09; 00000001 ~ 01111111 ——> 1~127&#xff08;从小到大&#xff…

Python需要学的基础有哪些

Python介绍 Python是一种广泛使用的高级编程语言&#xff0c;因其简洁易读的语法和强大的功能而备受欢迎。本文将介绍一些Python教学内容&#xff0c;帮助初学者快速入门编程世界 1. Python基础 Python的基础知识对于编程初学者至关重要。以下是一些重要的基础概念&#xff…

redis 持久化 与 键淘汰策略

redis运维核心&#xff1a; aof日志(全持久化 增量) 、 rdb(半持久化/全量备份) 、 键淘汰策略 、 高可用 1、Redis是基于内存的&#xff0c;一旦Redis重启/退出/故障&#xff0c;内存的数据将会全部丢失。故而有了持久化。 2、持久化&#xff1a;将内存中的数据存于磁盘中&am…

电脑第一次使用屏幕键盘

操作流程 1.在键盘上同时按WinR打开运行; 2.输入control 3.找到设置中心 4.点击屏幕键盘 效果 具体怎么使用 我不咋清除 简单 测试了一下 可以用鼠标点击屏幕键盘的按键 用键盘 按字母键和数字键 是和屏幕键盘不同步的 其他 tab、shift、后退、enter好像同步

stm32和python实现DMA+串口数据收发

STM32F103配置 1-0 串口配置 void uart_init(u32 bound){//GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART1时钟RCC_AP…