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

python——多线程编程(threading)

多线程是指在一个程序中同时执行多个独立的任务或操作。每个任务或操作都是由一个单独的线程来执行,而这些线程共享程序的资源和内存空间。Python 通过 threading 模块提供了对多线程的支持,使用 threading 模块可以方便地创建和管理线程。以下是几个使用 Python threading 库的案例,以帮助学习python的多线程编程

案例 1:基本的多线程任务

这个案例展示了如何创建多个线程来执行简单的任务

import threading
import timedef print_numbers():for i in range(5):time.sleep(1)print(i)def print_letters():for letter in 'abcde':time.sleep(1.5)print(letter)# 创建线程
t1 = threading.Thread(target=print_numbers)
t2 = threading.Thread(target=print_letters)# 启动线程
t1.start()
t2.start()# 等待线程完成
t1.join()
t2.join()print("所有线程执行完毕")

输出示例 :

案例 2:带参数的线程

这个案例展示了如何向线程传递参数

import threading
import timedef task(id, delay):print(f"任务 {id} 开始")time.sleep(delay)print(f"任务 {id} 完成")# 创建多个线程
threads = []
for i in range(1, 6):t = threading.Thread(target=task, args=(i, i * 0.5))threads.append(t)t.start()# 等待所有线程完成
for t in threads:t.join()print("所有任务完成")

输出示例 : 

案例 3:线程池

线程池是一种预先创建一组线程并保存在内存中的线程管理方式。当有任务到来时,线程池会从预创建的线程中选择一个执行任务,避免了线程的创建和销毁开销。这个案例展示了如何使用 ThreadPoolExecutor 来管理线程池。

使用场景

        1. 线程池:适用于 I/O 密集型任务,如网络请求、文件读写等。线程池适用于异步编程模型,可以有效地处理 I/O 密集型任务。

        2. 直接使用线程:适用于简单的并发任务,任务数量较少。

import concurrent.futures
import timedef worker(id):print(f"工作线程 {id} 开始")time.sleep(2)print(f"工作线程 {id} 完成")return f"结果来自 {id}"# 创建线程池
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:# 提交任务futures = [executor.submit(worker, i) for i in range(5)]# 获取结果for future in concurrent.futures.as_completed(futures):print(future.result())print("主线程继续运行")

案例 4:线程同步

为了确保代码的线程安全性,应该使用锁来保护对共享资源的访问。锁可以确保在同一时刻只有一个线程能够访问共享资源,从而避免竞态条件。这个案例展示了如何使用锁(Lock)来避免线程间的竞争条件。

下面的代码为对counter执行1000000次加一的操作,

如果不设置锁保证线程同步,代码如下:
 

import threading# 共享资源
counter = 0def increment():global counterfor _ in range(1000000):counter += 1# 创建多个线程
threads = []
for _ in range(10):t = threading.Thread(target=increment)threads.append(t)t.start()# 等待所有线程完成
for t in threads:t.join()print(f"不加锁的最终计数器值:{counter}")

输出如下:

不限制线程对counter的获取会获得不同的结果。

因此需要加锁,确保只有拿到钥匙的线程才能够对counter进行加一的操作,修改代码如下:

import threading# 共享资源
counter = 0
lock = threading.Lock()def increment():global counterfor _ in range(1000000):with lock:counter += 1# 创建多个线程
threads = []
for _ in range(10):t = threading.Thread(target=increment)threads.append(t)t.start()# 等待所有线程完成
for t in threads:t.join()print(f"加锁的最终计数器值:{counter}")

输出如下:

案例 5:守护线程

守护线程(Daemon Thread)是一种特殊的线程,主要用于在后台执行一些不需要用户直接干预的任务。当所有非守护线程(用户线程)结束时,程序会自动退出,无论守护线程是否完成其任务。这个案例展示了如何使用守护线程。

使用场景
  1. 日志记录:后台线程不断记录系统的运行状态。

  2. 数据抓取:周期性地从外部数据源获取数据。

  3. 定时任务:定时清理临时文件、缓存等

import threading
import timedef daemon_task():while True:print("守护线程运行中...")time.sleep(1)def main_task():print("主线程开始")time.sleep(5)print("主线程结束")# 创建守护线程
daemon = threading.Thread(target=daemon_task)
daemon.daemon = True  # 设置为守护线程# 创建主线程
main = threading.Thread(target=main_task)
main.start() # 开始主线程daemon.start() # 开始守护线程main.join()  # 等待主线程完成

输出示例:

 主线程结束后,守护线程会自动退出!

案例 6:threading.Event事件对象

在 Python 的 threading 模块中,Event(事件对象)是一种用于线程间通信的简单机制。它提供了一种线程同步的方式,通过一个内部标志来管理线程的执行状态。

事件对象的主要方法
  • is_set():当内置标志为 True 时返回 True

  • set():将标志设为 True,并通知所有处于等待阻塞状态的线程恢复运行状态。

  • clear():将标志设为 False

  • wait([timeout]):如果标志为 True 将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用 set()。可以通过 timeout 参数指定超时时间。

使用场景
  • 线程间的启动/停止信号:一个线程可以等待另一个线程发出开始或停止的信号。

  • 任务完成通知:一个线程完成一项任务后,通过设置事件通知其他相关线程。

  • 线程间的信号传递:通知其他线程某个条件已满足。

  • 同步启动:等待所有线程准备就绪后同时开始。

  • 定期检查:在循环中使用带超时的 wait 进行周期性检查。

  • 资源就绪通知:等待某个资源准备完毕。

6.1 视频的上传和下载:

import threading
import time# 创建一个事件对象
event = threading.Event()def download_video():print("开始下载视频")time.sleep(5)  # 模拟下载耗时print("视频下载完成,通知播放")event.set()def play_video():print("等待视频下载")event.wait()print("开始播放视频")# 创建并启动线程
download_thread = threading.Thread(target=download_video)
play_thread = threading.Thread(target=play_video)download_thread.start()
play_thread.start()download_thread.join()
play_thread.join()

输出示例:

6.2:定期检查

import threading
import time# 创建一个事件对象
event = threading.Event()def worker():while True:print("工人等待开始信号")event.wait(timeout=2)  # 每2秒检查一次if event.is_set():print("工人开始工作")event.clear()  # 清除事件else:print("工人继续等待")# 创建并启动线程
thread = threading.Thread(target=worker)
thread.start()# 模拟主线程设置事件
time.sleep(5)
event.set()  # 发送开始信号thread.join()

输出示例:

 

6.3 通知任务完成

import threading
import time
import random# 创建一个事件对象
event = threading.Event()
data = []def data_generator():global dataprint("数据生成器开始生成数据")for _ in range(5):time.sleep(random.randint(1, 2))data.append(random.randint(1, 100))print("数据生成完成,通知处理线程")event.set()def data_processor():print("数据处理器等待数据")event.wait()print("开始处理数据:", data)# 创建并启动线程
thread1 = threading.Thread(target=data_generator)
thread2 = threading.Thread(target=data_processor)thread1.start()
thread2.start()thread1.join()
thread2.join()

输出示例:

 

相关文章:

  • python实战:如何获取word文档中指定内容并作为新文件名
  • 鸿蒙 HarmonyOS NEXT 系统 Preference 首选项使用全解析
  • 偏微分方程数值方法指南及AI推理
  • springboot3+vue3融合项目实战-大事件文章管理系统-本地存储及阿里云oss程序集成
  • Linux操作系统的优势官方开发App应用程序有哪些优缺点
  • Java进阶之新特性
  • 中科视界,赋能文化产业新世界——千眼狼高速摄像机、DIC测量系统亮相第二十一届中国(深圳)国际文博会
  • VMIC PMV-5565PIORC-21000超高速光纤反射内存硬件参考
  • Argo CD 详解:从 GitOps 到持续交付的完整实践
  • Appium+python自动化(二)- 环境搭建—下
  • 鸿蒙 Initiated Worker with invalid NODE_OPTIONS env variable
  • N-gram语言模型原理与实战教程
  • Issac Lab安装
  • java I/O
  • SQLSERVER数据库表分区学习(未在项目上使用)
  • 地信GIS专业关于学习、考研、就业方面的一些问题答疑
  • HCIP-AI培养计划,成为新时代AI解决方案架构高级工程师
  • 【Dify学习笔记】:dify通过ollama加载DeepSeek-R1-32B模型无法加载!终于解决了!!
  • DL00786-基于RTDETR的水稻病害检测含完整数据集
  • C++函数封装和绑定
  • 义乌市建设局网站/友情链接的网站图片
  • 数据型网站建设/深圳最新新闻事件今天
  • 云南城乡建设厅网站/免费发布信息的网站平台
  • 网站外链建设工作计划/个人网页设计作品模板
  • 找人做销售网站/网站制作河南
  • 深圳市工程建设交易中心官网/深圳seo优化公司搜索引擎优化方案