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

Python3并发编程详解

日常开发中批量任务、接口请求、文件读写、爬虫抓取、数据计算等场景,串行执行效率低下,并发编程就是解决执行速度瓶颈的核心方案。

一、并发基础概念

1. 核心名词区分

  • 串行:任务挨个依次执行,前一个结束才运行下一个,效率最低
  • 并发:同一时间段交替处理多个任务,宏观同时运行,微观交替切换
  • 并行:同一时刻多核CPU同时执行多个任务,真正同时运行
  • 线程:轻量级执行单元,依附进程存在,共享进程资源,切换开销小
  • 进程:资源独立隔离,拥有独立内存空间,切换开销大
  • 协程:用户态轻量级任务,代码层面手动切换,无内核切换损耗

2. GIL全局解释器锁

Python独有锁机制,同一时刻一个进程内仅有一个线程执行

  • 限制:多线程无法利用多核CPU,CPU密集型任务多线程效率低
  • 适用:IO密集型(网络请求、文件读写、休眠等待)多线程优势明显

3. 任务场景选型

  • IO密集型:优先多线程 / 协程
  • CPU计算密集型:优先多进程
  • 高吞吐异步请求:优先asyncio协程

二、多线程编程 threading模块

1. 线程创建两种方式

方式一:函数式创建线程
importthreadingimporttimedeftask(name,delay):print(f"线程{name}开始执行,休眠{delay}秒")time.sleep(delay)print(f"线程{name}执行完毕")if__name__=='__main__':# 创建线程对象t1=threading.Thread(target=task,args=("一号",2))t2=threading.Thread(target=task,args=("二号",1))# 启动线程t1.start()t2.start()# 等待线程执行结束t1.join()t2.join()print("所有线程运行结束")
方式二:类继承创建线程
importthreadingimporttimeclassMyThread(threading.Thread):def__init__(self,name,delay):super().__init__()self.name=name self.delay=delaydefrun(self):print(f"线程{self.name}开始执行,休眠{self.delay}秒")time.sleep(self.delay)print(f"线程{self.name}执行完毕")if__name__=='__main__':t1=MyThread("线程A",1)t2=MyThread("线程B",2)t1.start()t2.start()t1.join()t2.join()

2. 线程守护

守护线程随主线程退出直接销毁,非守护线程执行完毕程序才结束

# daemon=True 设置为守护线程t=threading.Thread(target=task,daemon=True)

3. 线程安全与互斥锁

多线程共享全局变量,并发修改会出现数据错乱,使用Lock加锁保证原子性

importthreading num=0lock=threading.Lock()defadd_count():globalnum# 上锁lock.acquire()for_inrange(100000):num+=1# 释放锁lock.release()if__name__=='__main__':t1=threading.Thread(target=add_count)t2=threading.Thread(target=add_count)t1.start()t2.start()t1.join()t2.join()print("最终统计值:",num)

4. 线程池 ThreadPoolExecutor

避免无限创建线程资源耗尽,池化复用线程,管控并发数量

fromconcurrent.futuresimportThreadPoolExecutorimporttimedefwork(num):print(f"任务{num}执行中")time.sleep(1)returnf"任务{num}完成"if__name__=='__main__':# 设置最大并发线程数withThreadPoolExecutor(max_work=3)aspool:task_list=[pool.submit(work,i)foriinrange(6)]# 遍历获取执行结果forresintask_list:print(res.result())

三、多进程编程 multiprocessing模块

1. 进程基础创建

进程资源相互独立,默认不共享数据,规避GIL锁限制,适合计算密集型

importmultiprocessingimporttimedefprocess_task(name):print(f"进程{name}启动运行")time.sleep(2)print(f"进程{name}运行结束")if__name__=='__main__':p1=multiprocessing.Process(target=process_task,args=("P1",))p2=multiprocessing.Process(target=process_task,args=("P2",))p1.start()p2.start()p1.join()p2.join()print("全部进程执行完毕")

2. 进程间数据通信

使用队列Queue实现进程安全数据传递

frommultiprocessingimportProcess,Queuedefput_data(q):q.put("进程传递数据")defget_data(q):print("接收数据:",q.get())if__name__=='__main__':q=Queue()p1=Process(target=put_data,args=(q,))p2=Process(target=get_data,args=(q,))p1.start()p2.start()p1.join()p2.join()

3. 进程池 ProcessPoolExecutor

批量管理进程,充分利用多核CPU算力

fromconcurrent.futuresimportProcessPoolExecutorimportmathdefcalc_power(num):returnmath.pow(num,3)if__name__=='__main__':withProcessPoolExecutor(max_work=4)aspool:result=pool.map(calc_power,[1,2,3,4,5])print(list(result))

进程线程核心区别

  1. 内存:进程独立内存,线程共享进程内存
  2. 开销:进程创建销毁开销大,线程开销更小
  3. GIL:多进程突破GIL限制,线程受GIL约束
  4. 通信:进程通信复杂,线程共享变量通信简单

四、协程编程 asyncio

1. 协程基础概念

单线程内切换任务,无系统内核切换消耗,IO阻塞时自动切换其他任务,并发效率最高
关键字:async定义协程函数,await阻塞挂起任务

2. 基础协程写法

importasyncio# 定义协程函数asyncdefdemo1():print("协程任务1开始")awaitasyncio.sleep(2)print("协程任务1结束")asyncdefdemo2():print("协程任务2开始")awaitasyncio.sleep(1)print("协程任务2结束")asyncdefmain():# 创建并发任务t1=asyncio.create_task(demo1())t2=asyncio.create_task(demo2())awaitt1awaitt2# 运行协程入口asyncio.run(main())

3. 批量并发任务

importasyncioasyncdeftask_func(num):print(f"异步任务{num}执行")awaitasyncio.sleep(1)returnf"任务{num}完成"asyncdefmain():tasks=[task_func(i)foriinrange(5)]# 批量等待所有任务执行完毕res_list=awaitasyncio.gather(*tasks)print(res_list)asyncio.run(main())

4. 异步文件读写

适配协程风格文件操作,不阻塞异步流程

importaiofilesasyncdefread_file():asyncwithaiofiles.open("test.txt","r",encoding="utf-8")asf:content=awaitf.read()print(content)asyncio.run(read_file())

五、并发常见问题与解决方案

1. 死锁问题

多个线程互相持有对方所需锁,互相等待卡死

  • 解决:统一加锁顺序、减少嵌套锁、设置超时释放

2. 线程池/进程池参数设置

根据CPU核心数、IO阻塞程度合理设定最大并发数,避免阻塞雪崩

3. 并发异常捕获

批量任务中单独捕获异常,单个任务报错不影响整体流程

4. 三种并发选型总结

并发方式适用场景优缺点
多线程IO密集、网络请求、文件读写开销小,受GIL限制,无法多核计算
多进程CPU密集、大规模数值计算利用多核,资源开销大,通信繁琐
协程高并发IO、爬虫、异步接口效率最高,仅单线程运行,语法特殊

全文总结

本文详细介绍了串行 / 并发 / 并行、GIL 锁基础理论,覆盖多线程、多进程、协程三大并发实现方案。

http://www.zskr.cn/news/1520670.html

相关文章:

  • 2026 山东殡葬设备厂家怎么选,本地靠谱源头工厂口碑参考 —— 山东玲华环保科技实地可选 - 海棠依旧大
  • 线性f(Q)引力理论在致密天体建模中的应用
  • MC56F827xx DSC开发实战:时钟、复位与内存映射配置详解
  • 告别哑巴设备:手把手教你用STM32驱动SYN6288语音模块,实现智能语音播报
  • 不止是GPIO:深度挖掘Jetson TX2 NX的J21扩展口,玩转I2C传感器与SPI屏幕
  • 十八年代码耕耘,一名PHP程序员的自我修养
  • 084、NPU的随机计算(Stochastic Computing):低精度高鲁棒性
  • 项目部署到服务器教程
  • 新手必看:用Hypack 2023搭配R2Sonic多波束,从设备接线到数据采集的完整避坑指南
  • 触觉感知技术在农业采摘机器人中的应用与优化
  • 2026年更新:湖州不错的物流公司深度解析——湖州杭平物流有限公司 - 品牌鉴赏官2026
  • 2026年工业滑环市场观察:耐用的帽式滑环品牌与供应商推荐榜单 - 优质品牌商家
  • 3个关键功能解锁Mac睡眠管理新境界:SleeperX深度解析
  • SpringMVC 实现简易加法器
  • Mac触控板Windows驱动终极指南:如何在Windows 10/11上实现完美触控体验
  • UniApp项目实战:用uQRCode生成带动态Logo和样式切换的会员卡二维码
  • 深度实战:Python爬虫完美解析QQ音乐歌单——接口逆向分析与数据抓取全攻略
  • 2026年旅游招商加盟市场深度分析:哪些品牌值得关注? - 优质品牌商家
  • 别再自己造轮子了!用SKIT.FlurlHttpClient.Wechat.TenpayV3库,5分钟搞定C#微信Native支付
  • 如何在Mac上完美使用Xbox手柄:360Controller完整指南
  • 不用复杂环境配置 OpenClaw 一键部署流程完整拆解【附安装包】
  • SAP MM顾问必看:OBYC自动记账配置保姆级教程,从BSX到GBB一次讲透
  • 保姆级教程:用Python+Cartopy绘制专业气象图(以ERA5 500hPa位势高度场为例)
  • 开会不用埋头记!5款AI神器自动整理全套会议记录
  • 【课程设计/毕业设计】基于 SpringBoot 的校园家教信息平台的设计与实现高校校园家教服务信息平台【附源码、数据库、万字文档】
  • AI 时代,忙碌不再等于价值
  • 新手也能懂的DC-DC降压电路PCB布局:从MPQ8633A实战到自检清单
  • 别再只会生成黑白码了!用uQRCode在UniApp里玩转彩色、带Logo和边框的个性化二维码
  • 20250931在RK3399的Buildroot【linux-6.1】下关闭camera_engine_rkisp
  • Devin AI 自主式 AI 软件工程师智能体