一文速通Python并行计算:02 Python多线程编程-threading模块、线程的创建和查询与守护线程

一文速通 Python 并行计算:02 Python 多线程编程-threading 模块、线程的创建和查询与守护线程

image

摘要:

本文介绍了 Python threading 模块的核心功能,包括线程创建与管理、线程状态监控以及守护线程的特殊应用,重点讲解了 Thread 类的实例化方法、获取当前线程信息、检测线程存活状态,以及如何实现后台线程。

image

关于我们更多介绍可以查看云文档:Freak 嵌入式工作室云文档,或者访问我们的 wiki:****https://github.com/leezisheng/Doc/wik

原文链接:

FreakStudio的博客

往期推荐:

学嵌入式的你,还不会面向对象??!

全网最适合入门的面向对象编程教程:00 面向对象设计方法导论

全网最适合入门的面向对象编程教程:01 面向对象编程的基本概念

全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类

全网最适合入门的面向对象编程教程:03 类和对象的 Python 实现-为自定义类添加属性

全网最适合入门的面向对象编程教程:04 类和对象的Python实现-为自定义类添加方法

全网最适合入门的面向对象编程教程:05 类和对象的Python实现-PyCharm代码标签

全网最适合入门的面向对象编程教程:06 类和对象的Python实现-自定义类的数据封装

全网最适合入门的面向对象编程教程:07 类和对象的Python实现-类型注解

全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器

全网最适合入门的面向对象编程教程:09 类和对象的Python实现-类之间的关系

全网最适合入门的面向对象编程教程:10 类和对象的Python实现-类的继承和里氏替换原则

全网最适合入门的面向对象编程教程:11 类和对象的Python实现-子类调用父类方法

全网最适合入门的面向对象编程教程:12 类和对象的Python实现-Python使用logging模块输出程序运行日志

全网最适合入门的面向对象编程教程:13 类和对象的Python实现-可视化阅读代码神器Sourcetrail的安装使用

全网最适合入门的面向对象编程教程:全网最适合入门的面向对象编程教程:14 类和对象的Python实现-类的静态方法和类方法

全网最适合入门的面向对象编程教程:15 类和对象的 Python 实现-__slots__魔法方法

全网最适合入门的面向对象编程教程:16 类和对象的Python实现-多态、方法重写与开闭原则

全网最适合入门的面向对象编程教程:17 类和对象的Python实现-鸭子类型与“file-like object“

全网最适合入门的面向对象编程教程:18 类和对象的Python实现-多重继承与PyQtGraph串口数据绘制曲线图

全网最适合入门的面向对象编程教程:19 类和对象的 Python 实现-使用 PyCharm 自动生成文件注释和函数注释

全网最适合入门的面向对象编程教程:20 类和对象的Python实现-组合关系的实现与CSV文件保存

全网最适合入门的面向对象编程教程:21 类和对象的Python实现-多文件的组织:模块module和包package

全网最适合入门的面向对象编程教程:22 类和对象的Python实现-异常和语法错误

全网最适合入门的面向对象编程教程:23 类和对象的Python实现-抛出异常

全网最适合入门的面向对象编程教程:24 类和对象的Python实现-异常的捕获与处理

全网最适合入门的面向对象编程教程:25 类和对象的Python实现-Python判断输入数据类型

全网最适合入门的面向对象编程教程:26 类和对象的Python实现-上下文管理器和with语句

全网最适合入门的面向对象编程教程:27 类和对象的Python实现-Python中异常层级与自定义异常类的实现

全网最适合入门的面向对象编程教程:28 类和对象的Python实现-Python编程原则、哲学和规范大汇总

全网最适合入门的面向对象编程教程:29 类和对象的Python实现-断言与防御性编程和help函数的使用

全网最适合入门的面向对象编程教程:30 Python的内置数据类型-object根类

全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type

全网最适合入门的面向对象编程教程:32 Python的内置数据类型-类Class和实例Instance

全网最适合入门的面向对象编程教程:33 Python的内置数据类型-对象Object和类型Type的关系

全网最适合入门的面向对象编程教程:34 Python的内置数据类型-Python常用复合数据类型:元组和命名元组

全网最适合入门的面向对象编程教程:35 Python的内置数据类型-文档字符串和__doc__属性

全网最适合入门的面向对象编程教程:36 Python的内置数据类型-字典

全网最适合入门的面向对象编程教程:37 Python常用复合数据类型-列表和列表推导式

全网最适合入门的面向对象编程教程:38 Python常用复合数据类型-使用列表实现堆栈、队列和双端队列

全网最适合入门的面向对象编程教程:39 Python常用复合数据类型-集合

全网最适合入门的面向对象编程教程:40 Python常用复合数据类型-枚举和enum模块的使用

全网最适合入门的面向对象编程教程:41 Python常用复合数据类型-队列(FIFO、LIFO、优先级队列、双端队列和环形队列)

全网最适合入门的面向对象编程教程:42 Python常用复合数据类型-collections容器数据类型

全网最适合入门的面向对象编程教程:43 Python常用复合数据类型-扩展内置数据类型

全网最适合入门的面向对象编程教程:44 Python内置函数与魔法方法-重写内置类型的魔法方法

全网最适合入门的面向对象编程教程:45 Python实现常见数据结构-链表、树、哈希表、图和堆

全网最适合入门的面向对象编程教程:46 Python函数方法与接口-函数与事件驱动框架

全网最适合入门的面向对象编程教程:47 Python函数方法与接口-回调函数Callback

全网最适合入门的面向对象编程教程:48 Python函数方法与接口-位置参数、默认参数、可变参数和关键字参数

全网最适合入门的面向对象编程教程:49 Python函数方法与接口-函数与方法的区别和lamda匿名函数

全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类

全网最适合入门的面向对象编程教程:51 Python函数方法与接口-使用Zope实现接口

全网最适合入门的面向对象编程教程:52 Python函数方法与接口-Protocol协议与接口

全网最适合入门的面向对象编程教程:53 Python字符串与序列化-字符串与字符编码

全网最适合入门的面向对象编程教程:54 Python字符串与序列化-字符串格式化与format方法

全网最适合入门的面向对象编程教程:55 Python字符串与序列化-字节序列类型和可变字节字符串

全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用

全网最适合入门的面向对象编程教程:57 Python字符串与序列化-序列化与反序列化

全网最适合入门的面向对象编程教程:58 Python字符串与序列化-序列化Web对象的定义与实现

全网最适合入门的面向对象编程教程:59 Python并行与并发-并行与并发和线程与进程

一文速通Python并行计算:00 并行计算的基本概念

一文速通Python并行计算:01 Python多线程编程-基本概念、切换流程、GIL锁机制和生产者与消费者模型

更多精彩内容可看:

给你的 Python 加加速:一文速通 Python 并行计算

一文搞懂 CM3 单片机调试原理

肝了半个月,嵌入式技术栈大汇总出炉

电子计算机类比赛的“武林秘籍”

一个MicroPython的开源项目集锦:awesome-micropython,包含各个方面的Micropython工具库

Avnet ZUBoard 1CG开发板—深度学习新选择

工程师不要迷信开源代码,还要注重基本功

什么?配色个性化的电机驱动模块?!!

什么?XIAO主控新出三款扩展板!

手把手教你实现Arduino发布第三方库

万字长文手把手教你实现MicroPython/Python发布第三方库

文档获取:

可访问如下链接进行对文档下载:

https://github.com/leezisheng/Doc

该文档是一份关于 并行计算Python 并发编程 的学习指南,内容涵盖了并行计算的基本概念、Python 多线程编程、多进程编程以及协程编程的核心知识点:

image

正文

1.Python threading 模块

Python3 实现多线程编程需要借助于 threading 模块,threading 是 Python 标准库中的一个模块,它提供了一个高级的面向对象的线程编程接口。使用 threading 模块可以更方便地创建和管理线程,包括线程同步、线程通信、线程优先级等功能。(在 Python2 中,也有 thread 模块,它提供了一些基本的线程操作函数,例如 start_new_thread()函数用于创建新线程,exit()函数用于退出线程等。thread 模块只能在 Python 2 中使用。)

threading 模块包括以下组件:

  • (1)Thread 线程类,这是我们用的最多的一个类,你可以指定线程函数执行或者继承自它都可以实现子线程功能;
  • (2)Timer 与 Thread 类似,但要等待一段时间后才开始运行;
  • (3)Lock 锁,这个我们可以对全局变量互斥时使用;
  • (4)RLock 可重入锁,使单线程可以再次获得已经获得的锁;
  • (5)Condition 条件变量,能让一个线程停下来,等待其他线程满足某个“条件”;
  • (6)Event 通用的条件变量。多个线程可以等待某个事件发生,在事件发生后,所有的线程都被激活;
  • 7)Semaphore 为等待锁的线程提供一个类似“等候室”的结构;
  • (8)BoundedSemaphore 与 semaphore 类似,但不允许超过初始值;
  • (9)Queue:实现了多生产者(Producer)、多消费者(Consumer)的队列,支持锁原语,能够在多个线程之间提供很好的同步支持。

2.线程创建

使用线程最简单的一个方法是,用一个目标函数实例化一个 Thread 然后调用 start() 方法启动它。Python 的 threading 模块提供了 Thread() 方法在不同的线程中运行函数或处理过程等。

Thread 类代表一个在独立控制线程中运行的活动。该类提供的函数包括:

函数名称 作用
getName(self) 返回线程的名字
isAlive(self) 布尔标志,表示这个线程是否还在运行中
isDaemon(self) 返回线程的 daemon 标志
join(self, timeout=None) 程序挂起,直到线程结束,如果给出 timeout,则最多阻塞 timeout 秒
run(self) 定义线程的功能函数
setDaemon(self, daemonic) 用于设置线程是否为守护线程
setName(self, name) 设置线程的名字
start(self) 开始线程执行

一般来说,新建线程有两种模式,一种是创建线程要执行的函数,把这个函数传递进 Thread 对象里,让它来执行;另一种是直接从 Thread 继承,创建一个新的 class,把线程执行的代码放到这个新的 class 里。

2.1 调用 Thread 类的构造器创建线程

Thread 类提供了如下的 __init__() 构造器,可以用来创建线程:

__init__(self, group=None, target=None, name=None, args=(), kwargs=None, *,daemon=None)

此构造方法中,以上所有参数都是可选参数,即可以使用,也可以忽略。其中各个参数的含义如下:

  • group:指定所创建的线程隶属于哪个线程组;
  • target:当线程启动的时候要执行的函数;
  • name: 线程的名字,默认会分配一个唯一名字 Thread-N;
  • args:以元组的方式,为 target 指定的方法传递参数;
  • kwargs:以字典的方式,为 target 指定的方法传递参数;
  • daemon:指定所创建的线程是否为守护线程。

下面程序演示了如何使用 Thread 类的构造方法创建一个线程:

import threading
import timedef test():for i in range(5):print('test ',i)time.sleep(1)
thread = threading.Thread(target=test)
thread.start()
for i in range(5):print('main ', i)time.sleep(1)

上面代码很简单,在主线程上打印 5 次,在一个子线程上打印 5 次。

如下为代码输出,可以看到主线程和子线程交替执行:

image

2.2 继承 Thread 类创建线程类

通过继承 Thread 类,我们可以自定义一个线程类,从而实例化该类对象,获得子线程。需要注意的是,在创建 Thread 类的子类时,必须重写从父类继承得到的 run()方法。

import threading_#创建子线程类,继承自 Thread 类_
class MyThread(threading.Thread):def __init__(self):threading.Thread.__init__(self);_# 重写run()方法_def run(self):print("I am %s" % self.name)if __name__ == "__main__":for thread in range(0, 5):t = MyThread()t.start()

image

这里,线程启动有 start()join() 两种方法。用 start() 方法来启动线程,真正实现了多线程运行,这时无需等待 run 方法体代码执行完毕而直接继续执行后面的代码。

通过调用 Thread 类的 start() 方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到 cpu 时间片,就开始执行 run() 方法;join() 让调用它的线程一直等待直到执行结束(即阻塞调用它的主线程, t 子线程执行结束,主线程才会继续执行)。

在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到 join()方法了。

这里,我们看一下使用 join() 方法启动线程:

import threading
_#定义线程要调用的方法,*add可接收多个以非关键字方式传入的参数_
def action(*add):for arc in add:_#调用 getName() 方法获取当前执行该程序的线程名_print(threading.current_thread().name +" "+ arc)
_#定义为线程方法传入的参数_
my_tuple = ("http://c.biancheng.net/python/",\"http://c.biancheng.net/shell/",\"http://c.biancheng.net/java/")
_#创建线程_
thread = threading.Thread(target = action,args =my_tuple)
_#启动线程_
thread.start()
_#主线程执行如下语句_
for i in range(5):print(threading.current_thread().name)

程序执行结果为(不唯一):

image

可以看到,我们用 Thread 类创建了一个线程(线程名为 Thread-1),其任务是执行 action() 函数。同时,我们也给主线程 MainThread 安排了循环任务(第 16、17 行)。通过前面的学习我们知道,主线程 MainThread 和子线程 Thread-1 会轮流获得 CPU 资源,因此该程序的输出结果才会向上面显示的这样。

但是,如果我们想让 Thread-1 子线程先执行,然后再让 MainThread 执行第 16、17 行代码,该如何实现呢?很简单,通过调用线程对象的 join() 方法即可。

join() 方法的功能是在程序指定位置,优先让该方法的调用者使用 CPU 资源。该方法的语法格式如下:thread.join( [timeout] )

其中,thread 为 Thread 类或其子类的实例化对象;timeout 参数作为可选参数,其功能是指定 thread 线程最多可以霸占 CPU 资源的时间(以秒为单位),如果省略,则默认直到 thread 执行结束(进入死亡状态)才释放 CPU 资源。

3.确定当前的线程

每一个 Thread 都有一个 name 的属性,代表的就是线程的名字,这个可以在构造方法中赋值。如果在构造方法中没有个 name 赋值的话,默认就是 “Thread-N” 的形式,N 是数字。通过 thread.current_thread() 方法可以返回线程本身,然后就可以访问它的 name 属性。

import threading
import timedef test():for i in range(5):print(threading.current_thread().name+' test ',i)time.sleep(1)thread = threading.Thread(target=test)
thread.start()for i in range(5):print(threading.current_thread().name+' main ', i)time.sleep(1)

image

如果我们在 Thread 对象创建时,构造方法里面赋值:

thread = threading.Thread(target=test,name='TestThread')

image

4.查询线程是否还在运行

Thread 具有生命周期,创建对象时,代表 Thread 内部被初始化;调用 start() 方法后,thread 会开始运行;thread 代码正常运行结束或者是遇到异常,线程会终止。

可以通过 Thread 的 is_alive()方法查询线程是否还在运行。值得注意的是,is_alive() 返回 True 的情况是 Thread 对象被正常初始化,start()方法被调用,然后线程的代码还在正常运行。

import threading
import timedef test():for i in range(5):print(threading.current_thread().name+' test ',i)time.sleep(0.5)thread = threading.Thread(target=test,name='TestThread')
_# thread = threading.Thread(target=test)_
thread.start()for i in range(5):print(threading.current_thread().name+' main ', i)print(thread.name+' is alive ', thread.is_alive())time.sleep(1)

在上面的代码中,我们让 TestThread 比 MainThread 早一点结束,代码运行结果如下。

image

我们可以看到,主线程通过调用 TestThread 的 isAlive() 方法,准确查询到了它的存活状态。

5.守护线程的创建

Thread 的构造方法中有一个 daemon 参数。默认是 None。那么,daemon 起什么作用呢?我们先看一段示例代码。

import threading
import timedef test():for i in range(5):print(threading.current_thread().name+' test ',i)time.sleep(2)thread = threading.Thread(target=test,name='TestThread')
_# thread = threading.Thread(target=test,name='TestThread',daemon=True)_
thread.start()for i in range(5):print(threading.current_thread().name+' main ', i)print(thread.name+' is alive ', thread.is_alive())time.sleep(1)

我们让主线程执行代码的时长比 TestThread 要短,程序运行结果如下:

image

MainThread 没有代码运行的时候,TestThread 还在运行。这是因为 MainThread 在等待其他线程的结束。TestThread 中 daemon 属性默认是 False,这使得 MainThread 需要等待它的结束,自身才结束。

如果要达到,MainThread 结束,子线程也立马结束,怎么做呢?其实很简单,只需要在子线程调用 start() 方法之前设置 daemon 就好了。当然也可以在子线程的构造器中传递 daemon 的值为 True。

修改

thread = threading.Thread(target=test,name='TestThread')

thread = threading.Thread(target=test,name='TestThread',daemon=True)

image

可以看到 MainThread 结束了 TestThread 也结束了。也可以用 setDaemon 方法使得只要主线程完成了,不管子线程是否完成,都要和主线程一起退出。

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

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

相关文章

编程神器Trae:当我用上后,才知道自己的创造力被低估了多少

"AI会让每个人都能成为工具创造者,打破你能力边界,有时候只需要一个想法。" AI粉嫩特攻队,2025年3月23日。 前几天参加了一场行业闭门研讨会,满满1个半小时的干货演讲让我收获颇丰。会后,我迫不及待地想将录音整理成文字,方便日后回顾。却被提示"文件过大…

20244212喻浩川《Python程序设计》实验一报告

课程:《Python程序设计》 班级: 2442 姓名: 喻浩川 学号:20244212 实验教师:王志强 实验日期:2025年3月25日 必修/选修: 公选课 1.实验内容 (1)熟悉Python开发环境; (2)练习Python运行、调试技能; (3)编写程序,练习变量和类型、字符串、对象、缩进和注释等; (4)编写…

龙哥量化:deepseek写公式是需要思路的, 我整理的公式思路,请点赞收藏, 我持续更新ing

龙哥微信:Long622889代写技术指标_选股公式: 通达信,同花顺,东方财富,大智慧,文华,博易,飞狐代写量化策略: TB交易开拓者,文华8,金字塔AI写代码,很多朋友都试过了 deepseek,腾讯元宝,通义千问,豆包,chatgpt,通达信内嵌AI写公式,同花顺内嵌AI写公式,等等,写…

SciTech-EECS-Circuits-电路稳定性: 温度补偿 的几种方式对比: 响应时问、精度、动态范围、线性度、稳定度

电路稳定性: 温度稳定性 测试的几种方式:电吹风加热 冰箱(-5度) + 烤箱(50度/70度)改进 "文氏电桥振荡" 电路 的“热稳定性温度补偿” 网上找来找去,都是用FET(场效应管)做成"压控电阻"控制 "振荡器"的"增益",达到稳幅的目的。 但电…

SpringBoot3+Vue3实现查询功能

安装axios封装前后端对接数据工具npm i axios -S通过requst.js工具类发起请求import axios from "axios"; import {ElMessage} from "element-plus";const request = axios.create({baseURL:http://localhost:8080,//后端统一的请求地址timeout:30000 //后…

Apache Echarts 入门学习 -2025/3/24

介绍 一种数据可视化技术echats官方文档: https://echarts.apache.org/handbook/zh/get-started/ <!DOCTYPE html> <html> <head><meta charset="utf-8"><title>第一个 ECharts 实例</title><!-- 引入 echarts.js --><…

[数据资产/数据标准/行标] 电力数据交易分类分级管理规范(团体标准)

发布单位: 广东省网络空间安全协会附录A (资料性) 数据分类示例附录B (资料性) 数据分级示例附录C (规范性) 数据分级安全保护要求X 参考文献【团标】电力数据交易分类分级管理规范 - Weixin/数据工匠俱乐部本文作者:千千寰宇本文链接:https://www.cnblogs.com/johnnyzen关于…

Netty源码—5.Pipeline和Handler

大纲 1.Pipeline和Handler的作用和构成 2.ChannelHandler的分类 3.几个特殊的ChannelHandler 4.ChannelHandler的生命周期 5.ChannelPipeline的事件处理 6.关于ChannelPipeline的问题整理 7.ChannelPipeline主要包括三部分内容 8.ChannelPipeline的初始化 9.ChannelPipeline添加…

A important person

When I saw this title,the first “person” that came to mind was my little sister, my puppy dog called LaiBao. I still remember the first day I saw her. My mom bought it on internet and the solder took her to us. She was too small at that time. She curled…

模型2汇率的数据预处理环节

数据来源:中国银行官网 数据项:货币名称【欧元】、汇率、时间 数据预处理围绕四个方面展开:重复值、异常值、归一化、缺失值 由于数据来源于官方网站,本身不存在缺失值及异常值,通过观察样本数据可知,数据的波动范围在7.800~8.000之间【数据保存三位小数】,波动范围较小…

SciTech-EECS-Circuits-AGC(Auto Gain Control, 自动增益控制)电路 的几种方式对比: 响应时问、精度、动态范围、线性度、稳定度

参考 https://www.elecfans.com/article/83/116/2010/20101201227060.html AGC 的几种方式"误差放大器" 的 AGC(自动增益控制): 放大量小了,稳压效果不好,放大量大了,容易自激。 AGC重点参数: 响应时问、精度、动态范围、线性度、稳定度.用“直流电压负反馈方式”…

昆明理工大学25冶金工程考研预计调剂169人

--冶金工程考研809冶金物理化学有色冶金学有色金属冶金冶金过程及设备F002钢铁冶金学冶金调剂