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

Python 低层多线程接口_thread的用法

_thread是python标准库中的一个低层多线程API,可以在进程中启动线程来处理任务,并且提供了简单的锁机制来控制共享资源的同步访问。本文就_thread模块的用法和特性做个简单的演示。

文章目录

  • 一、进程和线程的区别
  • 二、_thread模块的用法
    • 2.1 派生线程
    • 2.2 同步化访问控制
    • 2.3 子线程的退出控制
      • 2.3.1 通过sleep等待子线程运行结束
      • 2.3.2 通过锁的状态监测子进程结束
      • 2.3.3 通过共享变量监测子进程结束

一、进程和线程的区别

并行(多任务处理)是现代操作系统的基本特性,一个程序可以同时处理很多任务而不被阻塞。多任务处理的基本方式有两种:进程分支和线程派生。

进程分支就是从当前进程复制一个程序副本,程序中的内存副本,文件描述符等都会被复制,子进程改变一个全局对象只是修改本地的副本,不会影响到父进程。常用在启动独立的程序。

线程派生和进程分支类似,但是子线程依然在原进程中运行,所有的子线程都会共享进程中的全局对象,相对于进程分支,少了一个"复制"的操作,因此更加轻量化,且由于共享进程对象,相当于自带了线程间的通信机制(进程间的通信则需要借助管道,套接字,信号等外部工具)。常用在处理一些轻量级任务。

但这些共享对象的访问可能出现冲突,_thread也提供了锁机制来同步化对象访问,例如修改一个对象时,先获取锁,完成后再释放,这样就可以保证任意时间点,最多能有1个线程能修改这个共享对象,防止出现混乱。

二、_thread模块的用法

_thread模块中的start_new_thread可以开启一个新的线程并运行指定程序。

2.1 派生线程

当程序启动时,其实它就已经启动了一个线程,这个就是主线程。通过_thread.start_new_thread方法,传入一个函数对象和一个参数元组,就可以开启新线程来执行所传入的函数对象。简单的演示如下:

import _thread as threaddef func(id):print('我是 {} 号子线程'.format(id))for i in range(5):thread.start_new_thread(func,(i,))

在这里插入图片描述

上面代码执行示意图如下:for循环执行了5次start_new_thread,这会开启5个线程,每个线程去执行func函数。因为线程是并行的,所以输出的顺序并不是0,1,2,3,4而是混乱的。注意3,4号子线程打印出现了重叠,这是因为它们共享一个标准输出流,而我们没有做同步化访问控制,因而它们同时打印输出。
在这里插入图片描述

2.2 同步化访问控制

由于子线程可以共享进程中的资源,这既是一个优势(方便线程间通信),也带来了共享资源访问的问题,如果多个子线程同时修改一个共享资源,那么就容易出现冲突,例如上面的输出重叠。

为了解决这类问题,_thread模块中的allocate_lock方法提供了一个简单的锁机制来控制共享访问,每次获取共享资源时先获取锁,可以保证任何时间点最多只有1个线程可以访问该资源。示例如下:

import _thread as threadlock = thread.allocate_lock()    # 定义一个锁def func(id):with lock:    # 用上下文管理器自动控制锁的获取和释放print('我是 {} 号子线程'.format(id))for i in range(5):thread.start_new_thread(func,(i,))

在这里插入图片描述

with lock会自动管理锁对象的获取和释放,默认线程会一直等待直到锁的获取,如果想要更精细的控制可以使用下面的方式:

lock.acquire()    # 获取锁
print('我是 {} 号子线程'.format(id))
lock.release()    # 释放锁

lock.acquire()有2个可选的参数:blocking=True代表无法获取锁时等待,blocking=False代表如无法立刻获取锁则返回。timeout=-1代表等待的秒数(-1代表无限等待),此参数只有在blocking设置为True时才能指定。

2.3 子线程的退出控制

_thread派生子线程后,如果主线程运行完毕,而子线程依然在运行中,那么所有子线程就会随着主线程的退出而被终止。

我们在子进程中增加一个sleep来模拟长时间任务,让其运行时长超过主线程。将下面的代码保存到一个thread1.py中,以一个独立进程启动:

import _thread as thread, timelock = thread.allocate_lock()    # 定义一个锁def func(id):time.sleep(id)    # 子线程会睡眠,运行时长将超过主线程with lock:print('我是 {} 号子线程'.format(id))for i in range(5):thread.start_new_thread(func,(i,))print('主线程结束,退出...')    # 主线程退出时打印提示

在这里插入图片描述

可以看到,主线程打印了退出提示,但子线程却没有任何输出,这是因为主线程运行的时间非常短,当其退出时,所有子线程都终止了。这种情况显然不是我们想看到的。示例图如下:
在这里插入图片描述

2.3.1 通过sleep等待子线程运行结束

为了解决上面的问题,一个简单的解决方案可以在主线程中加一个sleep,让其等待一段时间再退出,但这个时间我们只能预估。在上面的代码基础上,增加一个time.sleep(3),让主线程退出前等待3秒,保存为thread2.py,再次执行:

import _thread as thread, timelock = thread.allocate_lock()    # 定义一个锁def func(id):time.sleep(id)    # 子线程会睡眠,运行时长将超过主线程with lock:print('我是 {} 号子线程'.format(id))for i in range(5):thread.start_new_thread(func,(i,))time.sleep(3)    # 主线程等待3秒再退出
print('主线程结束,退出...')    # 主线程退出时打印提示

在这里插入图片描述
可以看到部分子进程运行完毕,但还有部分子进程未完成,因此这种方法不是很准确,虽然你可以给一个足够长的时间来保证所有子进程运行结束,但如果进程长时间不结束,也会占用系统资源。

2.3.2 通过锁的状态监测子进程结束

_thread.allocate_lock除了可以控制共享对象的访问,还可以用来传递全局状态,下面定义了包含5把锁的列表,每个子线程执行完成后会去获取其中对应位置上的锁,在主线程中通过lock.locked()来检查是否所有的锁都被获取,当所有锁都被获取时(代表所有子线程都结束),主线程退出。将下面代码保存到thread3.py中,再次运行:

import _thread as thread, timelock = thread.allocate_lock()    # 定义一个锁
exit_locks = [thread.allocate_lock() for I in range(5)]   # 定义一个列表,包含5把锁,对应稍后启动的5个子线程def func(id):time.sleep(id)    # 子线程会睡眠,运行时长将超过主线程with lock:print('我是 {} 号子线程'.format(id))exit_locks[id].acquire()    # 执行完成后获取exit_locks中对应位置的锁for i in range(5):thread.start_new_thread(func,(i,))for lock in exit_locks:while not lock.locked(): pass    # lock.locked()检测锁是否已被获取print('主线程结束,退出...')    # 主线程退出时打印提示

在这里插入图片描述
测试时可以发现,主线程会在所有子线程执行完毕后立刻退出,即不会提前导致子线程终止,也不会推迟浪费系统资源。

2.3.3 通过共享变量监测子进程结束

由于子线程可以共享进程中的变量,因此子线程中对共享对象的修改在主线程也可以看到,我们可以将上面的锁替换为简单的变量,可以达到相同的效果,下面使用一个共享列表,通过在子线程中修改变量值传递状态,将下面代码保存为thread4.py并执行:

import _thread as thread, timelock = thread.allocate_lock()    # 定义一个锁
exit_flags = [False]*5   # 定义一个全局共享列表,包含5个布尔变量Falsedef func(id):time.sleep(id)    # 子线程会睡眠,运行时长将超过主线程with lock:print('我是 {} 号子线程'.format(id))exit_flags[id] = True    # 执行完成后将共享列表中对应位置的值改为Truefor i in range(5):thread.start_new_thread(func,(i,))while False in exit_flags:pass    # 检测列表中是否有False,如果全部为Ture,代表所有子线程执行完毕print('主线程结束,退出...')    # 主线程退出时打印提示

在这里插入图片描述
可以看到主线程会等待子线程执行完毕后退出,这种方式相比上面可以节约锁分配的资源,看上去也更加简单。

以上即是_thread模块的基本用法。基于_thread模块还有高级的threading模块,_threading模块是基于类和对象的高级接口,并提供了额外的控制工具,例如threading.join()可以实现等待子进程退出。

相关文章:

Python 低层多线程接口_thread的用法

_thread是python标准库中的一个低层多线程API,可以在进程中启动线程来处理任务,并且提供了简单的锁机制来控制共享资源的同步访问。本文就_thread模块的用法和特性做个简单的演示。 文章目录 一、进程和线程的区别二、_thread模块的用法2.1 派生线程2.2…...

flutter基础 --dart语法学习

由于想要写一款性能较好,但是又可以一套代码多个平台运行的客户端app,所以选择了flutter 就去看了官方文档,大体发现flutter使用的dart语言和java和js差不多,感觉就是缝合怪。 Dart 是一种面向对象的编程语言,语法上与 Java、JavaScript 等语言有一些相似之处&…...

新手必看:一步步教你绑定常见邮箱到第三方应用(如何绑定QQ、163、Hotmail、Gmail等邮箱)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 邮箱绑定 📒📫 QQ邮箱📫 163邮箱📫 Hotmail邮箱📫 Gmail邮箱📫 Yahoo邮箱📫 iCloud邮箱📫 其他邮箱⚓️ 相关链接 ⚓️📖 介绍 📖 你是否曾经为绑定第三方邮箱而感到困惑?你不是一个人!许多人在尝试将QQ邮…...

mac 怎么查看CPU核数

在 macOS 系统中,可以通过以下几种方法查看 CPU 核心数: 1. 使用“关于本机”查看 点击左上角的苹果图标()。选择“关于本机”。在弹出的窗口中,系统会显示 Mac 的基本信息,包括 CPU 的类型和核心数。比…...

Vue生命周期;Vue路由配置;vue网络请求;vue跨域处理

一&#xff0c;Vue生命周期 <template><div > <h1 click"changeText">{{ info }}</h1></div> </template><script> export default {name: HelloWorld,data(){return{info:"介绍组件生命周期"}},methods:{chang…...

汽车电子电气架构从12V提升至48V,带来那些好处? 包括那些改变?

标签&#xff1a; 汽车电子电气架构&#xff1b; 从12V提升至48V&#xff1b; 汽车电子电气架构从12V提升至48V&#xff0c;带来那些好处&#xff1f; 包括那些改变&#xff1f; 将传统汽车的电子电气架构电压从12V提升至48V&#xff0c;既有显著的优势&#xff0c;也需要对车…...

springboot实战学习笔记(2)

目录 1、手动创建springboot工程&#xff0c;选择Maven构建。 2、Maven生成的&#xff0c;可能需要再main目录下new一个resources目录&#xff0c;再在其下目录new一个配置文件。 3、 pom文件中让当前的工程继承父工程依赖&#xff1a;、删去无用依赖。 4、引入后端环境所需要的…...

Python练习宝典:Day 1 - 选择题 - 基础知识

目录 一、踏上Python之旅二、Python语言基础三、流程控制语句四、序列的应用 一、踏上Python之旅 1.想要输出 I Love Python,应该使用()函数。 A.printf() B.print() C.println() D.Print()2.Python安装成功的标志是在控制台(终端)输入python/python3后,命令提示符变为: A.&…...

macOS平台(intel)编译MAVSDK安卓平台SO库

1.下载MAVSDK: git clone https://github.com/mavlink/MAVSDK.git --recursive 2.编译liblzma 修改CMakeLists.txt文件增加C与CXX指令-fPIC set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "-fPIC ${CMAKE_CXX_FLAGS}") 修改如下:…...

set的相关函数(3)

3.删除 //删除 /* int main() {set<int> s;s.insert({ 2,4,5,2,6,8,10,15 });for (auto e : s){cout << e << " ";}cout << endl;//删除最小的元素就删除排序后的首元素s.erase(s.begin());for (auto e : s){cout << e << "…...

Python MongoDB

MongoDB 是目前最流行的 NoSQL 数据库之一&#xff0c;使用的数据类型 BSON&#xff08;类似 JSON&#xff09;。 MongoDB 数据库安装与介绍可以查看我们的 MongoDB 教程。 PyMongo Python 要连接 MongoDB 需要 MongoDB 驱动&#xff0c;这里我们使用 PyMongo 驱动来连接。 …...

安国U盘量产工具系列下载地址

来源地址&#xff08;访问需要科学工具&#xff09;&#xff1a;AlcorMP (Последняя версия ALCOR U2 MP v23.08.07.00.H) – [USBDev.ru] 版本列表&#xff1a; AlcorMP&#xff08;最新版本的 ALCOR U2 MP v23.08.07.00.H&#xff09; AlcorMP是在Alcor Mic…...

2024年最新版Vue3学习笔记

本篇文章是记录来自尚硅谷禹神2023年课程的学习笔记&#xff0c;不得不说禹神讲的是真的超级棒&#xff01; 文章目录 创建Vue3工程main.ts文件解析初始化项目写一个简单的效果 Vue3核心语法setup函数setup和选项式的区别setup语法糖指定组件名称 响应式数据ref函数定义基本类…...

FX5 CPU模块和以太网模块的以太网通信功能

FX5 CPU模块和以太网模块的以太网通信功能的概要如下所示。 CPU模块的内置以太网端口的通信规格如下所示。 1、与MELSOFT的直接连接 不使用集线器&#xff0c;用1根以太网电缆直接连接以太网搭载模块与工程工具(GX Torks3)。无需设定IP地址&#xff0c;仅连接目标指定即可进行…...

【结构型】树形结构的应用王者,组合模式

目录 一、组合模式1、组合模式是什么&#xff1f;2、组合模式的主要参与者&#xff1a; 二、优化案例&#xff1a;文件系统1、不使用组合模式2、通过组合模式优化上面代码优化点&#xff1a; 三、使用组合模式有哪些优势1、统一接口&#xff0c;简化客户端代码2、递归结构处理方…...

C++——求3*3矩阵对角元素之和。

没注释的源代码 #include <iostream> using namespace std; int main() { int a[3][3],i,j,sum0; cout<<"请输入a组中的元素:"<<endl; for(i0;i<2;i) { for(j0;j<2;j) { cin>>a[i][j]…...

nodejs基于vue电子产品商城销售网站的设计与实现 _bugfu

目录 技术栈具体实现截图系统设计思路技术可行性nodejs类核心代码部分展示可行性论证研究方法解决的思路Express框架介绍源码获取/联系我 技术栈 该系统将采用B/S结构模式&#xff0c;开发软件有很多种可以用&#xff0c;本次开发用到的软件是vscode&#xff0c;用到的数据库是…...

GO Ants 学习

文章目录 主要特性安装基本用法1. 创建协程池并提交任务2. 带返回值的任务提交3. 自定义协程池的参数4. 获取协程池状态 应用场景优势资源释放性能对比总结 ants 是一个高性能的 Go 语言协程池库&#xff0c;专注于有效地管理 Go 协程的数量。它通过复用协程减少了创建和销毁协…...

Scikit-learn (`sklearn`) 教程

Scikit-learn (sklearn) 教程 Scikit-learn 是 Python 中最流行的机器学习库之一&#xff0c;提供了丰富的机器学习算法、数据预处理工具以及模型评估方法&#xff0c;广泛应用于分类、回归、聚类和降维等任务。 在本教程中&#xff0c;我们将介绍如何使用 Scikit-learn 进行…...

【计网】从零开始掌握序列化 --- JSON实现协议 + 设计 传输\会话\应用 三层结构

唯有梦想才配让你不安&#xff0c; 唯有行动才能解除你的不安。 --- 卢思浩 --- 从零开始掌握序列化 1 知识回顾2 序列化与编写协议2.1 使用Json进行序列化2.2 编写协议 3 封装IOService4 应用层 --- 网络计算器5 总结 1 知识回顾 上一篇文章我们讲解了协议的本质是双方能够…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...

基于鸿蒙(HarmonyOS5)的打车小程序

1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...