Python标准库 threading 的 start 和 join 的使用
python 的多线程机制可以的适用场景不适合与计算密集型的,因为 GIL 的存在,多线程在处理计算密集型时,实际上也是串行的,因为每个时刻只有一个线程可以获得 GIL,但是对于 IO 处理来说,不管是网络IO还是文件读写IO还是数据库IO,由于从用户态切换到内核态时,此时线程就陷入等待,线程让出对应 CPU,此时就可以切换到其他线程上继续执行任务,总的来说, python 的多线程机制适用于处理 IO 密集型任务。
这里引申出多线程机制的相关应用,python 的标准库中已经为我们提供了 threading模块,我们可以根据其中的 Thread类 进行线程的相关处理,主要就是创建,运行,阻塞,判断是否存活等操作:
- Thread(target=func, args=(), name=“myname”)
- Thread.is_alive()
- Thread.start()
- Thread.join()
但 python 的标准库的线程类仅提供了些简单操作,更多的线程控制,实际上并没有,比如针对超时或者对正在运行的线程停掉等,而且只要子线程 start() 后,其运行就脱离控制了,即使 join(timeout=10) 设置,也只是针对 is_alive() 进行属性的更改,这一点 golang 就在 goroutine 中做得很好,这里不是讨论重点。
接下来,我们就来看看线程类的使用吧。
1.start()后立即join()操作
很多刚使用 python 的人可能在 start() 后就立即 join(),这里会有问题,具体怎样呢,我们看看示例:
import time, datetime
import threading
import sysdef foo(sleep=2):print("当前thread: [{}]".format(threading.current_thread().name))time.sleep(sleep)print("thread: [{}] end.".format(threading.current_thread().name))def multiThread_v1():"""version1: 多个线程start后再join:return:"""print("[{}] [{}] start...".format(datetime.datetime.now(), sys._getframe().f_code.co_name))t1 = threading.Thread(target=foo, name="t1")t2 = threading.Thread(target=foo, name="t2")t3 = threading.Thread(target=foo, name="t3")t4 = threading.Thread(target=foo, name="t4")t5 = threading.Thread(target=foo, name="t5")t1.start()t1.join()t2.start()t2.join()t3.start()t3.join()t4.start()t4.join()t5.start()t5.join()print("[{}] [{}] end...".format(datetime.datetime.now(), sys._getframe().f_code.co_name))if __name__ == "__main__":multiThread_v1()
以下是运行结果:
[2023-04-13 10:40:55.820157] [multiThread_v1] start...
当前thread: [t1]
thread: [t1] end.
当前thread: [t2]
thread: [t2] end.
当前thread: [t3]
thread: [t3] end.
当前thread: [t4]
thread: [t4] end.
当前thread: [t5]
thread: [t5] end.
[2023-04-13 10:41:05.833481] [multiThread_v1] end...
可以看到本来我们创建5个子线程,想着可以并发跑,实际上是串行的,那多线程还有啥意义呢,还不如主线程里串行执行。
这里就要主要到 join() 的作用了,当 start() 后,子线程就开始运行了,我们通过调用 join(),这里就是阻塞主线程,告诉主线程,你得等我子线程运行完才能执行接下来的逻辑,多个子线程都这样,能不是串行执行了吗。
2.常见的应用
下面介绍一种常见的多线程的应用,通过下面的编码实现多线程执行并发的效果:
def multiThread_v3():print("[{}] [{}] start...".format(datetime.datetime.now(), sys._getframe().f_code.co_name))t_list = []for i in range(5):arg = 5 if i % 2 == 1 else 4t = threading.Thread(target=foo, args=(arg,), name="thread_"+str(i))t_list.append(t)for t in t_list:t.start()for t in t_list:t.join()print("[{}] [{}] end...".format(datetime.datetime.now(), sys._getframe().f_code.co_name))if __name__ == "__main__":multiThread_v3()
以下是执行结果:
[2023-04-13 10:46:28.393077] [multiThread_v3] start...
当前thread: [thread_0]
当前thread: [thread_1]
当前thread: [thread_2]
当前thread: [thread_3]
当前thread: [thread_4]
thread: [thread_4] end.thread: [thread_0] end.thread: [thread_2] end.thread: [thread_1] end.
thread: [thread_3] end.
[2023-04-13 10:46:33.395467] [multiThread_v3] end...
代码中通过设置几个sleep 5秒,几个sleep 4秒,模拟不同的处理耗时,可以看到,从开始到结束,线程单个时间总和应该是 4+5+4+5+4=22秒,实际上只运行5秒就全部结束了,我们还是回到 start() 和 join() 的功能上来分析,start() 后,都在跑子线程,通过 join(), 阻塞主线程,由于子线程都已经在运行,实际上的耗时取决于耗时最长的那个,也就是 sleep 5秒的的线程,所以 thread_0/2/4几乎同时结束,运行4秒,接着是thread_3/5,运行5秒,实际在业务时实现时,我们并不能预知耗时情况,比如涉及到网络抖动、磁盘IO等,所以通过遍历 join() 就更合理点。
补充
thread中join()函数的作用:如果thread是某个子线程,则调用thread.join()的作用是确保thread子线程执行完毕后才能执行下一个线程。下面第一个例子中没有调用join()函数,故没有这个限制,所有线程执行顺序都不定。
第二个例子中在每个子线程启动start()后马上调用了join()函数,这就确保了对于每一个子线程,必须等它执行完毕后才能执行下一个程序,故子线程是按顺序执行的,且主线程中的print()方法是在所有的子线程执行完毕后才执行。
第三个例子中,对于子线程启动start()后没有马上调用join()函数,故子线程的执行顺序是不确定的,但是主线程中的print()前调用了每个子线程的join()函数,故print()要在所有的子线程执行完毕后才能执行。
(1)没有使用join()函数,线程执行顺序不定,主线程可能在所有子线程执行完之前就执行了
(2)修改部分代码如下:每次启动子线程后,调用一次join()函数,可以看出线程按顺序执行,且主线程在所有子线程执行完之 后才执行。
(3)修改部分代码如下:可以看出子线程执行顺序不定,但是主线程是在所有子线程执行完毕之后才执行的。
参考文章:
python标准库threading
聊聊python的标准库 threading 的中 start 和 join 的使用注意事项
Python多线程:Threading中join()函数的理解
Python 多线程
相关文章:
Python标准库 threading 的 start 和 join 的使用
python 的多线程机制可以的适用场景不适合与计算密集型的,因为 GIL 的存在,多线程在处理计算密集型时,实际上也是串行的,因为每个时刻只有一个线程可以获得 GIL,但是对于 IO 处理来说,不管是网络IO还是文件…...

无公网IP 外网访问媒体服务器 Emby
Emby 是一款多媒体服务器软件,用户可以在 Emby 创建自己的个人多媒体娱乐中心,并且可以跨多个设备访问自己的媒体库。它允许用户管理传输自己的媒体内容,比如电影、电视节目、音乐和照片等。 本文将详细的介绍如何利用 Docker 在本地部署 Emb…...

【数据结构】_顺序表
目录 1. 概念与结构 1.1 静态顺序表 1.2 动态顺序表 2. 动态顺序表实现 2.1 SeqList.h 2.2 SeqList.c 2.3 Test_SeqList.c 3. 顺序表性能分析 线性表是n个具有相同特性的数据元素的有限序列。 常见的线性表有:顺序表、链表、栈、队列、字符串等;…...
[MySQL]数据库表内容的增删查改操作大全
目录 一、增加表数据 1.全列插入与指定列插入 2.多行数据插入 3.更新与替换插入 二、查看表数据 1.全列查询与指定列查询 2.查询表达式字段 3.为查询结果起别名 4.结果去重 5.WHERE条件 6.结果排序 7.筛选分页结果 8.插入查询的结果 9.group by子句 三、修改表数…...
解决双系统引导问题:Ubuntu 启动时不显示 Windows 选项的处理方法
方法 1:检查 GRUB 引导菜单是否隐藏 启动进入 Ubuntu 系统。打开终端,输入以下命令编辑 GRUB 配置文件:sudo nano /etc/default/grub检查以下配置项: GRUB_TIMEOUT0:如果是 0,将其改为一个较大的值&#x…...

Java面试题2025-Spring
讲师:邓澎波 Spring面试专题 1.Spring应该很熟悉吧?来介绍下你的Spring的理解 1.1 Spring的发展历程 先介绍Spring是怎么来的,发展中有哪些核心的节点,当前的最新版本是什么等 通过上图可以比较清晰的看到Spring的各个时间版本对…...

CentOS7安装使用containerd
一,安装 1.1、安装containerd 下载 https://github.com/containerd/containerd/releases/download/v1.7.24/cri-containerd-cni-1.7.24-linux-amd64.tar.gz wget https://github.com/containerd/containerd/releases/download/v1.7.24/cri-containerd-cni-1.7.24-…...

Redis 集群模式入门
Redis 集群模式入门 一、简介 Redis 有三种集群模式:主从模式、Sentinel 哨兵模式、cluster 分片模式 主从复制(Master-Slave Replication): 在这种模式下,数据可以从一个 Redis 实例(主节点 Master)复…...

WinDBG查找C++句柄泄露
C代码(频繁点击About按钮导致Mutex句柄泄露) HANDLE _mutexHandle;LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message){case WM_COMMAND:{int wmId LOWORD(wParam);// 分析菜单选择:switch (wmId){c…...

Linux查看服务器的内外网地址
目录: 1、内网地址2、外网地址3、ping时显示地址与真实不一致 1、内网地址 ifconfig2、外网地址 curl ifconfig.me3、ping时显示地址与真实不一致 原因是dns缓存导致的,ping这种方法也是不准确的,有弊端不建议使用,只适用于测试…...

深入MapReduce——引入
引入 前面我们已经深入了HDFS的设计与实现,对于分布式系统也有了不错的理解。 但HDFS仅仅解决了海量数据存储和读写的问题。要想让数据产生价值,一定是需要从数据中挖掘出价值才行,这就需要我们拥有海量数据的计算处理能力。 下面我们还是…...
Oracle之开窗函数使用
Oracle中的开窗函数(Window Functions)是一种强大的工具,用于在SQL查询中对数据进行复杂的分析和聚合操作,而无需改变原始查询结果的行数或顺序。以下是关于Oracle开窗函数的使用方法和常见示例: 1. 开窗函数的基本语法…...
航空客户价值的数据挖掘与分析(numpy+pandas+matplotlib+scikit-learn)
文章目录 航空客户价值的数据挖掘与分析(numpy+pandas+matplotlib+scikit-learn)写在前面背景与挖掘目标1.1 需求背景1.2 挖掘目标1.3 项目概述项目分析方法规划2.1 RFM模型2.2 LRFMC模型指标2.3 分析总体流程图数据抽取探索及预处理3.1 数据抽取3.2 数据探索分析3.3 数据预处…...

云原生时代,如何构建高效分布式监控系统
文章目录 一.监控现状二.Thanos原理分析SidecarQuerierStoreCompactor 三.Sidecar or ReceiverThanos Receiver工作原理 四.分布式运维架构 一.监控现状 Prometheus是CNCF基金会管理的一个开源监控项目,由于其良好的架构设计和完善的生态,迅速成为了监控…...

什么是CIDR技术? 它是如何解决路由缩放问题的
什么是CIDR技术? 它是如何解决路由缩放问题的 一. 什么是 CIDR?二. CIDR 是如何工作的?1. 高效地址分配2. 路由聚合(Route Aggregation)3. 精确满足需求 三. CIDR 的计算详解1. 子网掩码计算2. 地址范围计算3. 可用 IP…...

Unity URP 获取/设置 Light-Indirect Multiplier
Unity URP 获取/设置 Light-Indirect Multiplier 他喵的代码的字段名称叫:bounceIntensity ~~~~~~...

用Python和Tkinter标准模块建立密码管理器
用Python和Tkinter标准模块建立密码管理器 创建一个简单的密码管理器应用程序,帮助用户存储和管理他们的密码。使用Python的tkinter模块来创建一个图形用户界面(GUI)。 本程序支持 添加、查看、搜索、复制、修改、删除 功能。 本程序使用 …...

PyQt5菜单加多页签实现
pyqt tabs标签_哔哩哔哩_bilibili 代码实现 # coding:utf-8 import sys from PyQt5.QtCore import Qt from PyQt5 import QtCore,QtWidgets from PyQt5.QtWidgets import QApplication,QWidget from QhTabs01 import Ui_Form from PyQt5.Qt import *class QhLiangHuaGUI(QWidg…...
关注搜索引擎蜘蛛压力
以前在建站的时候,他们说蜘蛛来抓取的频率越多越好,因为蜘蛛来抓取说明了网站更新速度快,受搜索引擎的欢迎,但是在最近的网站统计中,发现很多蜘蛛爬取的频次非常的高,比如有的蜘蛛一天能来网站几万次&#…...
Python3 OS模块中的文件/目录方法说明三
一. 简介 前面文章简单学习了Python3中 OS模块中的文件/目录的部分函数。 本文继续来学习 OS模块中文件、目录的操作方法:os.fdopen()方法、os.fpathconf() 方法、os.fstat() 方法、os.fstatvfs() 方法。 二. Python3 OS模块中的文件/目录方法说明三 1. os.fdop…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...