引言

        在现代软件开发中,程序的执行效率至关重要。无论是处理大量数据、响应用户交互,还是与外部系统通信,常常需要让程序同时执行多个任务。Python作为一门功能强大且易于学习的编程语言,提供了多种并发编程方式,其中多线程(Multithreading) 是最常用的技术之一。

一、多线程简介

1.1 基本概念

  • 线程(Thread):是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
  • 多线程:指一个进程中同时运行多个线程,每个线程可以执行不同的任务。
  • 并发(Concurrency):多个任务微观上交替执行,宏观上给人“同时”运行的错觉。
  • 并行(Parallelism):多个任务真正同时执行(在多核CPU上)。

1.2 使用多线程的优势

  • 提高响应性:在GUI应用中,避免界面卡顿。
  • 提高吞吐量:同时处理多个I/O操作(如网络请求、文件读写)。
  • 资源共享:线程共享同一进程的内存空间,通信更高效。

二、Python中的多线程实现

Python标准库提供了 threading 模块来支持多线程编程。

创建线程

import threading
import timedef worker(name, delay):print(f"线程 {name} 开始")time.sleep(delay)print(f"线程 {name} 结束")# 创建线程
t1 = threading.Thread(target=worker, args=("A", 2))
t2 = threading.Thread(target=worker, args=("B", 3))# 启动线程
t1.start()
t2.start()# 等待线程结束
t1.join()
t2.join()print("所有线程执行完毕")

三、线程同步与通信

        多线程最大的挑战是共享资源的竞争。当多个线程同时访问和修改同一数据时,可能导致数据不一致。

3.1 使用 Lock(互斥锁)

import threading
import time# 共享资源
counter = 0
lock = threading.Lock()def increment():global counterfor _ in range(100000):with lock:  # 自动加锁和释放counter += 1# 创建多个线程
threads = []
for i in range(5):t = threading.Thread(target=increment)threads.append(t)t.start()for t in threads:t.join()print(f"最终计数: {counter}")  # 应为 500000

3.2 使用 RLock(可重入锁)

允许同一线程多次获取同一把锁。

lock = threading.RLock()def recursive_func(n):with lock:if n > 0:print(f"递归调用: {n}")recursive_func(n - 1)

3.3 使用 Condition(条件变量)

用于线程间的同步协调。

import threading
import timecondition = threading.Condition()
items = []def producer():for i in range(5):with condition:items.append(i)print(f"生产者添加: {i}")condition.notify()  # 通知等待的消费者time.sleep(0.1)def consumer():while True:with condition:while not items:condition.wait()  # 等待通知item = items.pop(0)print(f"消费者取出: {item}")if item == 4:break# 启动线程
t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)t1.start()
t2.start()t1.join()
t2.join()

四、线程池

对于需要频繁创建和销毁线程的场景,使用线程池可以显著提升性能。

from concurrent.futures import ThreadPoolExecutor
import requests
import timedef fetch_url(url):response = requests.get(url)return f"{url}: {response.status_code}"urls = ["https://httpbin.org/delay/1","https://httpbin.org/delay/2","https://httpbin.org/delay/1","https://httpbin.org/delay/3"
]# 使用线程池
start_time = time.time()with ThreadPoolExecutor(max_workers=3) as executor:results = list(executor.map(fetch_url, urls))for result in results:print(result)print(f"总耗时: {time.time() - start_time:.2f}秒")

优势

  • 复用线程,减少创建开销
  • 控制并发数量
  • 提供更简洁的API

五、Python多线程的局限性:GIL

5.1 什么是GIL?

全局解释器锁(Global Interpreter Lock) 是CPython解释器的一个互斥锁,它确保同一时刻只有一个线程执行Python字节码。

5.2 GIL的影响

  • CPU密集型任务:多线程无法真正并行,性能提升有限。
  • I/O密集型任务:线程在等待I/O时会释放GIL,因此多线程依然有效。

5.3 如何绕过GIL?

  • 使用 multiprocessing 模块(多进程)
  • 使用C扩展(如NumPy)
  • 使用Jython或PyPy等其他Python实现

六、最佳实践与注意事项

6.1 何时使用多线程?

  • I/O密集型任务(网络请求、文件操作、数据库查询)
  • GUI应用中保持界面响应
  • CPU密集型任务(应使用多进程)

6.2 安全注意事项

  • 始终使用锁保护共享数据
  • 避免死锁(按固定顺序获取锁)
  • 尽量减少锁的持有时间
  • 使用 with 语句确保锁的释放

6.3 调试技巧

  • 使用 threading.current_thread() 查看当前线程
  • 使用 threading.active_count() 查看活跃线程数
  • 使用日志记录线程行为

七、实际应用示例:并发下载器

import threading
import requests
from concurrent.futures import ThreadPoolExecutor
import timedef download_file(url, filename):try:response = requests.get(url, stream=True)with open(filename, 'wb') as f:for chunk in response.iter_content(8192):f.write(chunk)print(f"下载完成: {filename}")except Exception as e:print(f"下载失败 {filename}: {e}")# 多个文件下载
files = [("https://example.com/file1.zip", "file1.zip"),("https://example.com/file2.zip", "file2.zip"),("https://example.com/file3.zip", "file3.zip"),
]start_time = time.time()with ThreadPoolExecutor(max_workers=3) as executor:for url, filename in files:executor.submit(download_file, url, filename)print(f"全部下载完成,耗时: {time.time() - start_time:.2f}秒")

八、总结

Python多线程是处理I/O密集型任务的强大工具。通过本文的学习,你应该掌握了:

  • 如何创建和管理线程
  • 线程同步机制(Lock, Condition)
  • 使用线程池提升性能
  • 理解GIL的限制
  • 多线程的最佳实践

虽然GIL限制了Python多线程在CPU密集型任务中的表现,但在I/O密集型场景下,多线程依然是提高程序效率的首选方案。

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

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

相关文章

【JavaEE】(23) 综合练习--博客系统

一、功能描述 用户登录后,可查看所有人的博客。点击 “查看全文” 可查看该博客完整内容。如果该博客作者是登录用户,可以编辑或删除博客。发表博客的页面同编辑页面。 本练习的博客网站,并没有添加注册功能,以及上传作者头像功能…

MySQL全库检索关键词 - idea 工具 Full-Text Search分享

我们经常要在库中查找一个数据,又不知道在哪个表、哪个字段;或者想找到哪里有在用这个数据。我们可以用:idea 的 Database工具 - Full-Text Search打开idea,在工具栏找到 Database 然后新建自己的连接,然后右键&#x…

银行卡号识别案例

代码实现:import cv2 import numpy as np import argparse import myutils-i moban.png -t card1.pngap argparse.ArgumentParser() ap.add_argument("-i","--image", requiredTrue,help"path to input image") ap.add_argument(&quo…

云管平台上线只是开始:从“建好”到“用好”的运营、推广与深化指南

项目上线的喜悦转瞬即逝,随之而来的是一个更为现实和复杂的阶段:运营。云管平台(CMP)的成功,不再仅仅取决于其技术架构的先进性,更在于它能否融入组织的肌理,为不同角色持续创造价值。本文将从管理者、平台团队、开发者、运维和财务五个核心角色的视角,深入探讨平台上线…

distributed.client.Client 用户可调用函数分析

distributed.client.Client 用户可调用函数分析 1. 核心计算函数 任务提交和执行submit(func, *args, keyNone, workersNone, resourcesNone, retriesNone, priority0, fifo_timeout60s, allow_other_workersFalse, actorFalse, actorsFalse, pureNone, **kwargs) 提交单个函数…

数字图像处理——信用卡识别

在数字支付时代,信用卡处理自动化技术日益重要。本文介绍如何利用Python和OpenCV实现信用卡数字的自动识别,结合图像处理与模式识别技术,具有显著实用价值。系统概述与工作原理信用卡数字识别系统包含两大核心模块:模板数字预处理…

嵌入式ARM64 基于RK3588原生SDK添加用户配置选项./build lunch debian

1 背景 在我们正常拿到SDK后会有一些配置选项,在使用./build.sh lunch之后会输出一些defautconfig让我们选择,瑞芯微的原厂sdk会提供一些主板的配置选项,但是我们的如果是一块新的主板就需要添加自己的配置选项,本文就讨论如何来添…

专为石油和天然气检测而开发的基于无人机的OGI相机

专为石油和天然气检测而开发的基于无人机的OGI相机基于无人机的 OGI 相机:(Optical Gas Imaging,光学气体成像)其实是近几年油气、电力、化工等行业里非常热门的应用方向。什么是 OGI 相机OGI(Optical Gas Imaging)&am…

iPhone17全系优缺点分析,加持远程控制让你的手机更好用!

知名数码厂商苹果,不久前已官宣将于北京时间9月10日凌晨1点开启发布会,主打对于iPhone 17系列产品介绍,并且和以往不同的是,今年会在购物平台上开启线上直播,还是很有新意的。9.13全平台渠道将开启预售模式&#xff0c…

人工智能-python-深度学习-神经网络VGG(详解)

LeNet 系列之后 —— VGG(详解):从原理到 PyTorch 实现 文章目录LeNet 系列之后 —— **VGG(详解)**:从原理到 PyTorch 实现1. VGG 的发展历史与意义(一句话+背景)2. VGG…

光伏运维迎来云端革命!AcrelCloud-1200如何破解分布式光伏四大痛点?

在国家“双碳”目标推动下,分布式光伏正迎来爆发式增长🌞。甘肃、吉林、云南等多地政策接连落地,整县推进屋顶光伏试点如火如荼!然而,快速发展的背后,你是否也遇到过这些“光伏运维之痛”?✨【痛…

将 maven 集成到 idea 后出现 向项目创建模块时出错:null 的问题

1.出现的问题今天想将maven继承到idea出现了一下问题:用生成器里面的也会报错,找了找帖子并没有哪位大佬出现类似错误,于是我解决完想分享一下,如果有不对,请指正。2.解决办法很可能是java 的 版本 与 maven 版本有问题…

类似于 Progress Telerik Fiddler Classic 的 免费 或 开源 HTTP/HTTPS 抓包与调试工具推荐

以下是一些 类似于 Progress Telerik Fiddler Classic 的 免费 或 开源 HTTP/HTTPS 抓包与调试工具推荐:免费 / 开源替代工具推荐 1. Wireshark 免费且开源的网络协议分析工具,支持 Windows、macOS、Linux 等平台。可捕获并深入分析网络流量,…

7.0 热电偶的工作原理

在工业生产过程中,温度是需要测量和控制的重要参数之一。在温度测量中,热电偶的应用极为广泛,它具有结构简单、制造方便、测量范围广、精度高、惯性小和输出信号便于远传等许多优点。另外,由于热电偶是一种无源传感器,…

commons-lang3

概述 提供了许多帮助程序实用程序&#xff0c;特别是字符串操作方法&#xff0c;基本数值方法&#xff0c;对象反射&#xff0c;并发&#xff0c;创建和序列化以及系统属性。maven依赖<dependency><groupId>org.apache.commons</groupId><artifactId>c…

vue-amap组件呈现的效果图如何截图

我们用amap呈现了几个图层后&#xff0c;用户觉得效果很好&#xff0c;想点个按钮直接将这个画面截图下来。 首先我们用Canvas的toDataURL方法可以直接获取图像数据&#xff0c;但是实践发现截图后是空白的。 原因在警告中&#xff1a; 地图的WebGL context 的preserveDrawin…

杰理烧录ERROR: Data error after erasing, address = 0x430000

把CONFIG_BOARD_DEV_KIT关闭&#xff0c;打开CONFIG_BOARD_DEVELOP

超越自动化:为什么说供应链的终局是“AI + 人类专家”的混合智能?

摘要&#xff1a;当前&#xff0c;围绕AI赋能供应链的讨论&#xff0c;大多聚焦于“自动化”带来的降本增效。然而&#xff0c;这仅仅是第一层。当我们的系统面对“黑天鹅”事件时&#xff0c;一个过度依赖自动化的“脆弱”系统可能会瞬间崩溃。本文旨在深入探讨供应链演进的下…

Spine文件导入Unity流程

1、转为Json文件导出 2、对文件进行处理 3、添加Spine的Package包 一、Spine文件导出设置 1、选择Json文件 2、选择导出所在路径 3、点击打包设置 更改图集扩展名 二、文件导出后的设置 1、修改Json的Spine版本 这里必须是3.8 三、下载Unity支持包 1、链接 spine-unit…

Docker Compose healthcheck介绍(监控容器中服务的实际健康状态)数据库健康检查pg_isready

文章目录**功能概述****核心参数详解****配置示例****1. 基础用法****2. 使用数据库健康检查****3. 结合 depends_on 控制启动顺序****高级用法****1. 自定义健康检查脚本****2. 多种健康检查类型**- **HTTP 检查**&#xff1a;- **TCP 端口检查**&#xff1a;- **Redis 检查**…