python线程(python threading模块、python多线程)(守护线程与非守护线程)

文章目录

    • Python多线程入门
      • 1. Python多线程概述
      • 2. `threading`模块基础
        • - Thread 类: 这是一个代表线程的类。可以通过创建`Thread`类的实例来新建一个线程。
        • - Lock 类: 在多线程环境中,为了防止数据错乱,通常需要用到锁机制。`Lock`类提供了基本的锁功能,可以帮助同步线程。
        • - Condition 类: 这是一种更高级的线程同步机制,它在某些条件下阻塞线程,直到被其他线程唤醒。
      • 3. 创建线程
      • 4. 线程间通信
      • 5. 线程同步
    • Python Threading模块各类详解
      • Thread 类
        • - target:指定线程启动时要执行的函数。
        • - args:是一个元组,表示传递给目标函数的参数。
        • - kwargs:是一个字典,表示传递给目标函数的关键字参数。
        • - name:为线程指定一个名称,这在调试时很有用。
        • - daemon:布尔值,指示线程是否是守护线程(守护线程会随着主线程的退出而退出)。
          • 参数
          • 守护线程的特性
          • 示例(守护线程与非守护线程)
            • - 守护线程(主程序退出守护线程将会被强制退出):
            • - 非守护进程(主程序退出,非守护线程照样执行,直到它自己运行完)
        • 示例:
      • Lock 类
        • - acquire(blocking=True, timeout=-1):尝试获得锁。`blocking`参数为`False`时,方法会立即返回一个布尔值,表示是否获取到了锁。`timeout`指定等待锁的最长时间。
        • - release():释放锁。
        • 示例:
      • Semaphore 类
        • - acquire(blocking=True, timeout=-1):同`Lock`的`acquire`。
        • - release():释放信号量。
        • 示例:
      • Event 类
        • - set():将事件状态设置为真。
        • - clear():将事件状态设置为假。
        • - wait(timeout=None):阻塞线程,直到事件的状态为真或超时。
        • 示例:
      • Condition 类
        • - acquire() / release():与Lock相同,用于获取和释放底层锁。
        • - wait(timeout=None):调用线程等待,直到被notify()或notify_all()唤醒或超时。
        • - notify(n=1):唤醒一个或多个正在等待这个条件的线程。`n` 指定要唤醒的线程数。
        • - notify_all():唤醒所有等待这个条件的线程。
        • 示例:
      • Barrier 类
        • - parties:这是Barrier类构造函数的主要参数,代表需要到达屏障点的线程数。只有当指定数量的线程都已调用了wait()方法,所有这些线程才会同时被释放继续执行。这个数字必须在创建Barrier时确定,并在其生命周期内保持不变。
        • - wait():阻塞调用此方法的线程,直到所有线程都已调用此方法。然后所有线程同时释放。
        • 示例:
      • Timer 类
        • - interval:定时器激活之前的延迟时间(秒)。
        • - function:定时器激活时要执行的函数。
        • - args / kwargs:传递给 function 的参数。
        • 示例:
      • 参考文章

Python多线程入门

1. Python多线程概述

Python多线程是一种允许程序同时执行多个任务的技术。它主要通过threading模块实现,该模块提供了丰富的API来创建和管理线程。使用多线程可以提高程序的执行效率,尤其是在执行多个独立的任务时,或者在进行大量的I/O操作时。

2. threading模块基础

threading模块是Python中用于实现多线程的标准库之一。这个模块中包含了多个类和函数,可以帮助开发者创建和管理线程。

- Thread 类: 这是一个代表线程的类。可以通过创建Thread类的实例来新建一个线程。
- Lock 类: 在多线程环境中,为了防止数据错乱,通常需要用到锁机制。Lock类提供了基本的锁功能,可以帮助同步线程。
- Condition 类: 这是一种更高级的线程同步机制,它在某些条件下阻塞线程,直到被其他线程唤醒。

3. 创建线程

创建线程的基本方法是实例化Thread类,它接受一个目标函数和函数的参数。下面是一个简单的示例:

import threadingdef print_numbers(n):for i in range(1, n + 1):print(i)# 创建线程
thread = threading.Thread(target=print_numbers, args=(10,))
# 启动线程
thread.start()
# 等待线程完成
thread.join()

在这里插入图片描述

这段代码定义了一个打印数字的函数,并在一个新线程中运行这个函数。

4. 线程间通信

线程间的通信可以通过全局变量、队列等方式实现。Python的queue.Queue类是线程安全的,非常适合用来进行线程间的数据传递。

import threading
import queue# 创建一个队列
q = queue.Queue()def producer():for i in range(10):q.put(i)print(f"Produced {i}")def consumer():while True:item = q.get()if item is None:breakprint(f"Consumed {item}")q.task_done()# 创建生产者和消费者线程
t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)t1.start()
t2.start()t1.join()
q.put(None)  # 用None来通知消费者结束
t2.join()

在这里插入图片描述

5. 线程同步

在多线程环境中,线程同步是非常重要的。这可以通过锁(Lock)来实现。下面的示例展示了如何使用锁来确保多个线程可以安全地修改共享数据。

import threading# 共享资源
counter = 0
lock = threading.Lock()def update_counter():global counterwith lock:current = countercurrent += 1counter = currentprint(f"Counter: {counter}")threads = []
for i in range(10):t = threading.Thread(target=update_counter)t.start()threads.append(t)for t in threads:t.join()

在这里插入图片描述

注意:t.join() 是一个阻塞调用。当在一个线程中调用 join() 方法时,它会阻塞调用它的线程(通常是主线程),直到被 join() 的线程(即 t)执行完毕。这意味着主线程将等待 t 线程结束其执行,然后才继续执行 join() 之后的代码。

join() 方法通常用于确保线程在程序继续执行之前完成其任务,特别是当主线程需要从其他线程中获得结果或确保所有子线程在继续之前完成时。这是一种同步技术,用于协调不同线程间的执行顺序。

这段代码创建了10个线程,每个线程都尝试更新全局变量counter。通过锁lock,确保了每次只有一个线程可以修改counter


确实,之前的回答中只是简要介绍了threading模块的一些基础用法。下面将详细介绍threading模块中几个重要的类和函数,以及它们的参数和用法:

Python Threading模块各类详解

Thread 类

Thread类是threading模块中用来创建和管理线程的主要类。主要参数如下:

- target:指定线程启动时要执行的函数。
- args:是一个元组,表示传递给目标函数的参数。
- kwargs:是一个字典,表示传递给目标函数的关键字参数。
- name:为线程指定一个名称,这在调试时很有用。
- daemon:布尔值,指示线程是否是守护线程(守护线程会随着主线程的退出而退出)。
参数

在 Python 的 threading 模块中,daemon 属性是用来指定线程是否为守护线程(daemon thread)。这个属性接受一个布尔值,用来定义线程的行为:

  • True:线程被设置为守护线程。守护线程在程序退出时不会阻止程序的终止。也就是说,当主程序结束时,所有的守护线程将被强制终止,无论是否运行完成。
  • False:线程被设置为非守护线程(默认值)。非守护线程必须在程序退出前完成或被显式地结束,否则程序会等待这些线程结束后才能完全退出。
守护线程的特性

守护线程通常用于在后台运行的服务或任务,如日志写入、系统监控等。这些任务通常是周期性的,不需要和程序主逻辑同步结束。设置线程为守护线程可以防止这些后台任务延长主程序的生命周期。

示例(守护线程与非守护线程)

下面的代码示例演示了如何设置守护线程,并观察守护线程与非守护线程的行为差异:

- 守护线程(主程序退出守护线程将会被强制退出):
import threading
import timedef daemon_thread():while True:time.sleep(1)print("Daemon thread is running...")# 创建守护线程
daemon = threading.Thread(target=daemon_thread)
daemon.daemon = True# 启动线程
daemon.start()print("Main program exits.")

在这里插入图片描述

- 非守护进程(主程序退出,非守护线程照样执行,直到它自己运行完)
import threading
import timedef non_daemon_thread():for i in range(5):time.sleep(1)print("Non-daemon thread is running...")# 创建非守护线程
non_daemon = threading.Thread(target=non_daemon_thread)# 启动线程
non_daemon.start()print("Main program exits.")

在这里插入图片描述

示例:
import threadingdef worker(num):"""线程执行的目标函数"""print(f"Worker: {num}")threads = []
for i in range(5):t = threading.Thread(target=worker, args=(i,), name=f"thread-{i}")t.start()threads.append(t)for t in threads:t.join()

在这里插入图片描述

Lock 类

Lock类用于线程同步,主要方法有:

- acquire(blocking=True, timeout=-1):尝试获得锁。blocking参数为False时,方法会立即返回一个布尔值,表示是否获取到了锁。timeout指定等待锁的最长时间。
- release():释放锁。
示例:
import threadinglock = threading.Lock()def worker(num):lock.acquire()try:print(f"Worker: {num}")finally:lock.release()threads = []
for i in range(5):t = threading.Thread(target=worker, args=(i,))t.start()threads.append(t)for t in threads:t.join()

在这里插入图片描述

Semaphore 类

信号量是一种更高级的同步机制,允许多个线程同时访问相同的资源,但有限制的数量。

- acquire(blocking=True, timeout=-1):同Lockacquire
- release():释放信号量。
示例:
import threadingsemaphore = threading.Semaphore(2)def worker(num):with semaphore:print(f"Worker: {num}")threads = []
for i in range(5):t = threading.Thread(target=worker, args=(i,))t.start()threads.append(t)for t in threads:t.join()

在这里插入图片描述

Event 类

事件是一个简单的同步机制,主要用于线程间的事件通知。

- set():将事件状态设置为真。
- clear():将事件状态设置为假。
- wait(timeout=None):阻塞线程,直到事件的状态为真或超时。
示例:
import threadingevent = threading.Event()def waiter(event, n):print(f"Thread {n} waiting for event")event.wait()print(f"Thread {n} proceeding")def setter(event):print("Setting event")event.set()t1 = threading.Thread(target=waiter, args=(event, 1))
t2 = threading.Thread(target=waiter, args=(event, 2))
t3 = threading.Thread(target=setter, args=(event,))t1.start()
t2.start()
t3.start()t1.join()
t2.join()
t3.join()

在这里插入图片描述

当然,threading 模块除了包括 Thread, Lock, Semaphore, 和 Event 类外,还有其他一些有用的同步原语和工具,可以帮助解决线程之间的协调和状态共享问题。下面介绍几个其他常用的类:

Condition 类

Condition类用于复杂的线程同步问题。本质上,它是一个围绕锁(Lock)的更高级的锁,允许一个线程等待某个条件,而让其他线程发出条件已满足的信号。

- acquire() / release():与Lock相同,用于获取和释放底层锁。
- wait(timeout=None):调用线程等待,直到被notify()或notify_all()唤醒或超时。
- notify(n=1):唤醒一个或多个正在等待这个条件的线程。n 指定要唤醒的线程数。
- notify_all():唤醒所有等待这个条件的线程。
示例:
import threadingcondition = threading.Condition()def consumer(cond):with cond:print("Consumer waiting")cond.wait()print("Consumer proceed")def producer(cond):with cond:print("Producer ready, notifying consumer")cond.notify_all()t1 = threading.Thread(target=consumer, args=(condition,))
t2 = threading.Thread(target=producer, args=(condition,))t1.start()
t2.start()t1.join()
t2.join()

在这里插入图片描述

Barrier 类

Barrier类用于创建一个同步点,线程必须同时到达这个点才能继续执行。这在某些并行算法中非常有用,需要所有并行任务同时到达某个计算阶段后才能继续。

- parties:这是Barrier类构造函数的主要参数,代表需要到达屏障点的线程数。只有当指定数量的线程都已调用了wait()方法,所有这些线程才会同时被释放继续执行。这个数字必须在创建Barrier时确定,并在其生命周期内保持不变。
- wait():阻塞调用此方法的线程,直到所有线程都已调用此方法。然后所有线程同时释放。
示例:
import threadingbarrier = threading.Barrier(2)def worker(barrier, num):print(f"Worker {num} reaching barrier")barrier.wait()print(f"Worker {num} passed barrier")t1 = threading.Thread(target=worker, args=(barrier, 1))
t2 = threading.Thread(target=worker, args=(barrier, 2))t1.start()
t2.start()t1.join()
t2.join()

在这里插入图片描述

Timer 类

TimerThread 的子类,用于在指定的时间后启动一个操作。

- interval:定时器激活之前的延迟时间(秒)。
- function:定时器激活时要执行的函数。
- args / kwargs:传递给 function 的参数。
示例:
import threadingdef delayed_function():print("Timer activated")timer = threading.Timer(5.0, delayed_function)
timer.start()  # 5秒后,打印输出

在这里插入图片描述

这些类提供了不同的同步机制,使得多线程程序可以更加精细地控制线程间的交互和协调。在设计多线程应用时,了解和选择合适的同步机制是非常重要的,可以帮助避免死锁和竞争条件等问题。


这些类和方法为Python中的多线程编程提供了丰富的支持,使得可以在多种场景下有效地使用线程。


以上内容是对Python多线程的一个基础介绍,涵盖了创建线程、线程间通信和线程同步的基本概念和方法。在实际应用中,根据具体需求选择合适的同步机制和通信方式是非常重要的。

参考文章

参考文章:python线程创建和传参(33)

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

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

相关文章

本地搭建我的世界服务器(JAVA)简单记录

网上参考教程挺多的,踩了不少坑,简单记录一下,我做的是一个私人服务器,就是和朋友3、4个人玩。 笨蛋 MC 开服教程 先放一个比较系统和完整的教程,萌新可用,这个教程很详细,我只是记录一下自己的…

【C++】list容器的基本使用

一、list是什么 list的底层结构是带头双向循环链表。 相较于 vector 的连续线性空间,list 就显得复杂很多,它是由一个个结点构成,每个结点申请的空间并不是连续的,它的好处是每次插入或删除一个数据,就配置或释放一个…

禁忌搜索算法(TS算法)求解实例---旅行商问题 (TSP)

目录 一、采用TS求解 TSP二、 旅行商问题2.1 实际例子:求解 6 个城市的 TSP2.2 **求解该问题的代码**2.3 代码运行过程截屏2.4 代码运行结果截屏(后续和其他算法进行对比) 三、 如何修改代码?3.1 减少城市坐标,如下&am…

游戏如何对抗定制挂

近年来,游戏安全对抗强度相比以往更加激烈,具体表现在“定制挂”趋势显著。在近期收集的近万款外挂样本中,定制挂约占比78%,常见的内存修改器、变速器等通用作弊手段占比正在下降。 所谓定制挂,是指针对某款游戏单独开…

初写MySQL四张表:(2/4)

今天,我们来写第二张表。因着这四张表以及后续有相应的拓展,这四张环环相扣,所以还未写出第一张表的同学,可以看完第一张表,再来此处: 初写MySQL四张表:(1/4)-CSDN博客 好,今日表格有三张&…

easy-es动态索引支持

背景 很多项目目前都引入了es,由于es弥补了mysql存储及搜索查询的局限性,随着技术的不断迭代,原生的es客户端使用比较繁琐不直观,上手代价有点大,所以easy-es框架就面世了,学习成本很低,有空大…

记忆化搜索专题——算法简介力扣实战应用

目录 1、记忆化搜索算法简介 1.1 什么是记忆化搜索 1.2 如何实现记忆化搜索 1.3 记忆化搜索与动态规划的区别 2、算法应用【leetcode】 2.1 题一:斐波那契数 2.1.1 递归暴搜解法代码 2.1.2 记忆化搜索解法代码 2.1.3 动态规划解法代码 2.2 题二&#xff1…

vue-使用refs取值,打印出来是个数组??

背景: 经常使用$refs去获取组件实例,一般都是拿到实例对象,这次去取值的时候发现,拿到的竟然是个数组。 原因: 这是vue的特性,自动把v-for里面的ref展开成数组的形式,哪怕你的ref名字是唯一的&#xff01…

后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0916)

接口文档: https://apifox.com/apidoc/shared-26c67aee-0233-4d23-aab7-08448fdf95ff/api-93850835 接口根路径: http://big-event-vue-api-t.itheima.net 本项目的技术栈 本项目技术栈基于 ES6、vue3、pinia、vue-router 、vite 、axios 和 element-plus http:/…

6.C++程序中的基本数据类型

数据类型是指在C中用于声明不同类型变量或函数的一个系统或抽象或者是一个分类,它决定了变量存储占用的内存空间以及解析存储的位模式。其实数据类型可以理解为固定内存大小的别名,是创建变量的模具,具体使用哪种模具(包括自定义&…

Python安装不再难!全平台保姆级教程带你轻松搞定!

Python介绍 Python是一种功能强大且灵活的编程语言,被广泛应用于各个领域。以下是Python在不同应用领域的一些常见用途: 网络开发 Python提供了丰富的库和框架,使其成为网络开发的理想选择。诸如Django、Flask和Pyramid等框架可以帮助开发人员…

一张图解析FastAdmin中的表格列表(bootstrap-table)的功能(备份)

功能描述 请根据图片上的数字索引查看对应功能说明。 1.菜单名称和描述 默认生成的CRUD是没有菜单名称和描述显示的,如果需要显示则可以修改权限管理->菜单规则,给对应菜单的添加上备注信息后即可显示,支持HTML 2.TAB过滤选项卡 在一键…

Linux之CentOS 7.9-Minimal部署Oracle 11g r2 安装实测验证(桌面模式)

前言: 发个之前的库存… Linux之CentOS 7.9-Minimal部署Oracle 11g r2 安装实测验证(桌面模式) 本次验证的是CentOS_7_Minimal-2009桌面模式来部署Oracle 11g r2,大家可根据自身环境及学习来了解。 环境:下载地址都给你们超链好了 1、Linux系统镜像包: 1.1 CentOS-7-x86_…

Linux 删除文件不释放空间问题处理

背景: 服务器磁盘空间已经达到100%,删除存放日志路径下的文件后,发现空间并未释放! 原因:在linux系统中,通过rm删除文件将会从文件系统的文件夹结构上解除链接(unlink)然后删除,然而假设文件是被…

探索Python的Excel世界:openpyxl的魔法之旅

文章目录 探索Python的Excel世界:openpyxl的魔法之旅背景:为什么选择openpyxl?什么是openpyxl?如何安装openpyxl?简单的库函数使用方法场景应用:openpyxl在实际工作中的应用常见bug及解决方案总结 探索Pyth…

如何利用视觉分析实现扬尘检测

随着城市化和工业化进程的加速,扬尘污染已成为全球各大城市面临的环境问题之一。建筑施工、道路交通以及工业活动产生的扬尘不仅影响空气质量,严重时还会引发呼吸道疾病,威胁公众健康。传统的扬尘检测手段多为传感器、采样仪等设备&#xff0…

【Echarts】vue3打开echarts的正确方式

ECharts 是一个功能强大、灵活易用的数据可视化工具,适用于商业报表、数据分析、科研教育等多种场景。那么该如何优雅的使用Echarts呢? 这里以vue3为例。 安装echarts pnpm i echarts封装公用方法 // ts-nocheck import * as echarts from echarts; // 我们这里借…

【C++指南】inline内联函数详解

💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《C指南》 期待您的关注 目录 引言 C为什么引入了inline来替代C语言中的宏 inline的基本用法 定义inline函数 inline的优势与…

IO模型---BIO、NIO、IO多路复用、AIO详解

本篇将想给详细解释一下什么是BIO、NIO、IO多路复用以及AIO~ 同步的阻塞(BIO)和非阻塞(NIO)的区别 BIO:线程发来IO请求后,一直阻塞着IO线程,需要缓冲区这边数据准备好之后,才会进行下一步的操作。 举个🌰&#xff1…

HarmonyOS应用开发者基础认证

目录 一、判断二、单选三、多选 一、判断 1、HarmonyOS提供了基础的应用加固安全能力,包括混淆、加密和代码签名能力。正确 2、可以通过ohpm uninstall 指令下载指定的三方库。错误 3、支持模块化开发是指一个应用通常会包含多种功能,将不同的功能特性…