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

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()

输出示例:

 

http://www.xdnf.cn/news/8274.html

相关文章:

  • 【工具】Quicker/VBA|PPT 在指定位置添加有颜色的参考线
  • 交叉编译DirectFB报错解决方法
  • Day 28 训练
  • nginx和docker常用指令
  • thinkpad x220降频到0.7Ghz解决办法
  • 遥控器芯片6nm与3nm技术对比!
  • 如何将吉客云奇门数据无缝对接金蝶云星空
  • 远程升级方案(经通讯管理机)
  • 怎么有效降低知网AIGC率?
  • 华为RH1288HV3 BMC忘记用户名密码如何恢复默认
  • 华为仓颉语言如何进行交叉编译
  • 第三十二天打卡
  • 构建基于全面业务数据的大数据与大模型企业护城河战略
  • 【Linux】网络基础3
  • JUC入门(五)
  • 进程、线程和协程切换的比喻
  • 【分治】归并排序:递归版 非递归版
  • IDC机房交换机紧急更换的流程和注意事项
  • torch.gather()和torch.sort
  • 火语言UI组件--控件函数调用
  • 免费开源的图片分割小工具
  • RT-Thread源码阅读(1)——基本框架
  • 通过云服务器实现异地组网 部署WireGuard
  • 【机器学习】 关于外插修正随机梯度方法的数值实验
  • 听脑AI:革新沟通方式,开启高效信息时代
  • 核实发票的真实性与合法性-发票查验接口-虚假发票防范
  • 关于Newtonsoft版本不兼容问题处理
  • sentinel滑动时间窗口算法详解
  • 系统性能分析基本概念(3) : Tuning Efforts
  • imuerrset