threading库:Python线程的基础知识

article/2025/10/6 16:27:33

目录

  • 前言
  • Thread对象
  • 区分线程
  • 守护线程
  • 自定义线程
  • 定时器线程
  • 线程间传送信号

前言

前面的subprocess库主要讲解的是进程知识与进程间的交互。而进程有可以拥有多个线程,所以threading库提供了管理多个线程执行的API,允许程序在同一个进程空间并发地运行多个操作。

本篇,将详细的介绍Python线程库:threading。

Thread对象

要使用threading库,最简单的方式是使用Thread,它可以直接通过函数实例化一个Thread对象,并调用start让它工作。毕竟,我们用线程也是为了执行耗时任务,把任务封装到一个函数中,直接创建往往最简单。

示例如下:

import threadingdef print1tonum(num):for i in range(10000):print(i)t = threading.Thread(target=print1tonum,args=(10000,))
t.start()

运行之后,效果如下:
线程基础

这里,我们创建了一个线程,并向它传递参数告诉它要完成什么工作。

区分线程

一般来说,我们创建线程是避免在主线程中处理耗时的任务,但是有时候,就算是基本的运算任务,因为其叠加起来非常的多,我们会考虑用多个线程进行处理。示例如下:

import threading
import timedef printThreadName1():print(threading.current_thread().getName() + " start")time.sleep(0.2)print(threading.current_thread().getName() + ' end')def printThreadName2():print(threading.current_thread().getName() + " start")time.sleep(0.2)print(threading.current_thread().getName() + ' end')def printThreadName3():print(threading.current_thread().getName() + " start")time.sleep(0.2)print(threading.current_thread().getName() + ' end')t1 = threading.Thread(name='t1', target=printThreadName1)
t2 = threading.Thread(name='t2', target=printThreadName2)
t3 = threading.Thread(name='t3', target=printThreadName3)
t1.start()
t2.start()
t3.start()

运行之后,效果如下:
顺序有问题

这里,我们会发现print打印非常的混乱,虽然3个线程都是一摸一样的,但结束的时候并不是按顺序结束的,因为它们是同时运行的。(这里需要注意,更多内容接着往下看)

守护线程

运行上面的代码我们会发现,主程序都是在等线程运行完成之后,才结束的。也就是说,创建线程的主程序,无法在线程结束前安全退出。那么,可不可保证运行线程时,主线程可以退出呢?

答案是可以的,这个时候我们需要用到守护线程,这个线程可以一直运行而不阻塞主程序的退出,比如在服务器监控的工具线程,对于这些服务,守护线程往往更有用。

要构造守护线程,需要将上面创建线程的方式增加一个参数daemon,它是一个布尔值,默认值为False,普通线程,改为True就是守护线程。

import threading
import timedef printThreadName1():print(threading.current_thread().getName() + " start")time.sleep(0.2)print(threading.current_thread().getName() + ' end')def printThreadName2():print(threading.current_thread().getName() + " start")time.sleep(0.2)print(threading.current_thread().getName() + ' end')def printThreadName3():print(threading.current_thread().getName() + " start")time.sleep(0.2)print(threading.current_thread().getName() + ' end')t1 = threading.Thread(name='t1', target=printThreadName1, daemon=True)
t2 = threading.Thread(name='t2', target=printThreadName2)
t3 = threading.Thread(name='t3', target=printThreadName3)
t1.start()
t2.start()
t3.start()

运行之后,效果如下:
守护线程
可以看到,博主这里将t1设置为守护线程,但是没有看到t1结束主程序就结束了。如果需要等待一个守护线程完成工作,可以增加join()函数。

t1 = threading.Thread(name='t1', target=printThreadName1, daemon=True)
t2 = threading.Thread(name='t2', target=printThreadName2, daemon=True)
t3 = threading.Thread(name='t3', target=printThreadName3, daemon=True)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()

输出结果就不展示了,与前文非守护的线程一样。

需要注意的是,join()函数会无限阻塞,直到线程任务结束。当然,如果想设置一个最大的等待时间,超过时间就不在等待也行。

示例如下:

t1 = threading.Thread(name='t1', target=printThreadName1, daemon=True)
t2 = threading.Thread(name='t2', target=printThreadName2, daemon=True)
t3 = threading.Thread(name='t3', target=printThreadName3, daemon=True)
t1.start()
t2.start()
t3.start()
t1.join(0.4)
print(t1.is_alive())
t2.join()
t3.join()

这里,设置了t1等待最长时间为0.4秒,读者可以将t1线程的运行时间增加到1秒,看看其效果,is_alive()的意义是等待了0.4秒后,t1是否还在运行,为True代表是的,如下所示:
效果图

需要注意的是join()可能会造成死锁。比如现在有3个线程t1,t2,t3,t1需要使用资源12,t2需要使用资源23,t3需要使用资源13,3个同时运行。开始时,t1在使用资源1等待资源2,t2在使用资源2等待资源3,t3在使用资源3等待资源1,它们互相等待对方释放资源,但都不释放,导致循环等待下去,形成死锁。(与主线程等待线程结束差不多的道理)

自定义线程

从上面的所有线程运行,想必读者肯定发现了一个问题,那就是threading.Thread无法提供返回值。而实际的多线程运行中,往往我们都是获取网络数据,然后再处理,所以必须获取其处理的结果。

这个时候,自定义线程就能实现该需求,示例如下:

import threading
import requestsclass GetHTMLThread(threading.Thread):def __init__(self, args, kwargs):super(GetHTMLThread, self).__init__()self.args = argsself.kwargs = kwargsdef run(self):print(self.args)self.result = requests.get(url=self.kwargs['url'])def get_result(self):return self.result.textt = GetHTMLThread(args=(1,), kwargs={'url': "https://www.baidu.com"})
t.start()
t.join()
print(t.get_result())

运行之后,效果如下:
线程自定义

定时器线程

在我们使用django搭建服务器时,往往有许多的延时触发任务。比如我们CSDN就是我们搭建的博客网站,那么我们定时更新博客就是一个延时任务,我昨天写完博客,希望明天下午18点发送,那么这个延时任务就是中间的时差。

那么,此时我们使用定时器线程往往效果更好。示例如下:

import threadingdef getWeather():print("更新博客")t1 = threading.Timer(0.3, getWeather)
t1.setName('t1')
t2 = threading.Timer(0.3, getWeather)
t2.setName('t2')t1.start()
t2.start()
t2.cancel()

运行之后,效果如下:
定时器任务

这里会延迟0.3秒执行线程,而之所以t2线程没有执行,是因为我们调用了cancel()函数,取消了该线程的执行。

线程间传送信号

尽管使用多线程的目的是并发地运行单独的任务,但有时候也需要在多个线程间同步操作。而Python中,线程的通信方法是事件对象。

Event管理一个内部标志,调用者可以用set()和clear()方法控制这个标志。其他线程可以使用wait()暂停,直到这个标志被设置,可以有效的阻塞进程直到允许这些线程继续。

import threading
import timedef wait_for_event(e):print("wait_for_event")event_is_set = e.wait()print("wait_for_event", event_is_set)def wait_for_event_timeout(e, t):while not e.is_set():print("wait_for_event_timeout")event_is_set = e.wait(t)print("wait_for_event_timeout", event_is_set)if event_is_set:print("运行任务")else:print('运行其他任务')e = threading.Event()
t1 = threading.Thread(name='t1',target=wait_for_event,args=(e,)
)
t1.start()
t2 = threading.Thread(name='t2',target=wait_for_event_timeout,args=(e, 2)
)
t2.start()
time.sleep(5)
e.set()

运行之后,效果如下:
线程2

这个例子中,wait_for_event_timeout()函数将检查事件状态而不会无限阻塞。wait_for_event()在wait()调用的位置阻塞,事件状态改变之前它不会返回。

因为后面的线程知识还有很多,但这篇博文已经很长了,所以接下来的锁,释放锁等知识,将在下一个threading库章节讲解。


http://chatgpt.dhexx.cn/article/jj1OgrNT.shtml

相关文章

Python Threading 线程模块用法

一、什么是 Threading Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、恢复、中断。 1.1、线程池图解 二、创建线程 导入模块threading,通过…

python中threading模块_python中threading模块详解

python中threading模块详解,threading提供了一个比thread模块更高层的API来提供线程的并发性。这些线程并发运行并共享内存。 下面来看threading模块的具体用法: 一、Thread的使用 目标函数可以实例化一个Thread对象,每个Thread对象代表着一个线程,可以通过start()方法,开…

python中的threading_python中threading的用法

threading提供了一个比thread模块更高层的API来提供线程的并发性。这些线程并发运行并共享内存。 下面来看threading模块的具体用法: 一、Thread的使用 目标函数可以实例化一个Thread对象,每个Thread对象代表着一个线程,可以通过start()方法…

Python--threading多线程总结

转载自:https://www.cnblogs.com/tkqasn/p/5700281.html threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。python当前版本的多线程库没有实现优先级、线程组,线程也不能被停止、暂停、恢复、中断。 threading模块提供的类&…

Python 批量创建线程及threading.Thread类的常用函数及方法

在《【Python】线程的创建、执行、互斥、同步、销毁》(点击打开链接)中介绍了Python中线程的使用,但是里面线程的创建,使用了很原始的方式,一行代码创建一条。其实,Python里是可以批量创建线程的。利用Pyth…

功能强大的python包(十一):threading (多线程)

1.threading简介 threading库是python的线程模型,利用threading库我们可以轻松实现多线程任务。 2.进程与线程简介 通过上图,我们可以直观的总结出进程、线程及其之间的关系与特点: 进程是资源分配的最小单元,一个程序至少包含…

一文搞明白Python多线程编程:threading库

目录 前言一、基础知识1、并行和并发(1)定义(2)联系 2、进程和线程(1)定义(2)联系 3、全局解释器锁GIL 二、threading库1、线程的使用(1)普通创建方式&#x…

分块矩阵求逆(推导)

关于分块矩阵求逆,其中对角矩阵比较简单,我看很多人都写了,并且很详细。 但关于AUVD的分块矩阵我没看到太让我明白的,可能我get不到点,数学基础差,我就自己写了详细的步骤。 我写的这个条件是A可逆&#…

伴随矩阵求逆矩阵

在之前的文章《线性代数之矩阵》中已经介绍了一些关于矩阵的基本概念,本篇文章主要就求解逆矩阵进行进一步总结。 余子式(Minor) 我们先看例子来直观的理解什么是余子式(Minor,后边将都用英文Minor,中文的翻译较乱)。 minor exa…

矩阵的逆

矩阵的逆 原理&#xff1a; 连接&#xff1a; https://baike.baidu.com/item/%E9%80%86%E7%9F%A9%E9%98%B5 代码&#xff1a; QT c版&#xff1a; //求逆矩阵 QVector<QVector<double>> Matrix_inverse(QVector<QVector<double>> &A) {int …

矩阵求逆

矩阵求逆 初等变换求逆参考文章 初等变换求逆 1&#xff09;初等变换求逆矩阵时不能同时使用初等列变换和初等行变换&#xff0c;使用初等列变换或者初等行变换来求逆矩阵都是可以的&#xff0c;但是不能二者同时使用&#xff0c;只能用一种方法来得到逆矩阵。 2&#xff09;初…

卡西欧计算器矩阵求逆

记录一下&#xff0c;防止忘记 1 按开机键 打开计算器 2 按 菜单设置键 进去计算模式选择模块 3 按“ 4 ”选择矩阵运算 4 有四个矩阵可以编辑 选择按 4 编辑矩阵D 5 输入矩阵的行数 我按了3 6 输入矩阵的列数 我按了 3 7 建了一个3*3空矩阵 输入第一个数 12 然后按“”键完…

如何用计算机求矩阵的逆矩阵,逆矩阵的求法

逆矩阵是数学知识的一种&#xff0c;很多学习数学的同学们应该很了解吧。逆矩阵计算器是一款可以对矩阵的逆进行计算的免费程序,本程序引入了分数算法,可以对分数元素计算并得出分数结果。那么这款软件怎么样呢&#xff1f;接下来&#xff0c;介绍一下。 逆矩阵的求法 A^(-1)(1…

python求逆矩阵的方法,Python 如何求矩阵的逆

我就废话不多说了,大家还是直接看代码吧~ import numpy as np kernel = np.array([1, 1, 1, 2]).reshape((2, 2)) print(kernel) print(np.linalg.inv(kernel)) 注意,Singular matrix奇异矩阵不可求逆 补充:python+numpy中矩阵的逆和伪逆的区别 定义: 对于矩阵A,如果存在一…

Maple矩阵求逆

如何使用Maple进行矩阵求逆 调用包 with(LineAlgebra);输入我想要的矩阵&#xff1a; R : Matrix([[cos(a), sin(a), 0], [-sin(a), cos(a), 0], [0, 0, 1]]);然后我使用了Inverse命令 simplify(Inverse(R));结果并没有生成矩阵的逆。 查了一下说明手册加上mod好像也不行&a…

线性代数 --- 矩阵求逆的4种方法

线性代数 --- 矩阵求逆的4种方法 写在最前面&#xff1a;在大多数情况下&#xff0c;我们学习线性代数的目的是为了求解线性方程组Axb&#xff0c;而不是为了求A的逆。 单就解方程而言&#xff0c;LU分解是最实用的算法。只需按照ALU——>Axb,LUxb——>Lyb(正向回代求得y…

求解逆矩阵的常用三种方法

1.待定系数法 矩阵A 1, 2 -1,-3 假设所求的逆矩阵为 a,b c,d 则 从而可以得出方程组 a 2c 1 b 2d 0 -a - 3c 0 -b - 3d 1 解得 a3; b2; c -1; d -1 2.方程组求逆矩阵 伴随矩阵是矩阵元素所对应的代数余子式&#xff0c;所构成的矩阵&#xff0c;转置后得到的新矩阵。 …

矩阵求逆四种方法

注&#xff1a; 用A、B表示某矩阵, E表示单位矩阵 用Aˊ表示A逆 用|A|表示A的行列式 &#xff3b;A|E&#xff3d;表示拼接矩阵 一、公式法 先求A行列式结果&#xff0c;再求A伴随矩阵&#xff0c;最后再求A逆矩阵 |A| &#xff01; 0 则 AˊA*/|A| 注&#xff1a;图片中det…

浏览器渲染页面和加载页面机制

为什么有些网站打开的时候会加载会很慢&#xff0c;而且是整个页面同时显示的&#xff0c;而有些网站是从顶到下逐步显示出来的&#xff1f;弄懂这些对前端性能优化有很大帮助。要搞懂这个可以先从下面这个常规流程开始&#xff1a; 常规流程 1. 浏览器下载的顺序是从上到下&am…

页面实现加载进度条

文章目录 一、定时器实现进度条二、css3实现进度条三、加载状态事件实现进度条 一、定时器实现进度条 原理&#xff1a;设置了固定的时间后将图片和遮罩层隐藏,显示出页面的内容 效果1&#xff1a; 定时器实现的进度条效果 代码实现 <!DOCTYPE html> <html langen>…