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

python进程,线程与协程

一、多任务的概念

什么是多任务:多任务是指在同⼀时间内执⾏多个任务

我们之前所写的程序都是单任务的,也就是说⼀个函数或者⽅法执⾏完成 , 另外⼀个函 数或者⽅法才能执⾏。要想实现多个任务同时执⾏就需要使⽤多任务。

多任务的最⼤好处是充分利 ⽤CPU资源,提⾼程序的执⾏效率

多任务的两种表现形式:

① 并发 ② 并⾏

二、并发与并行

1、并发

概念:在⼀段时间内交替去执⾏多个任务。

- 多个任务在同一个时间段内交替执行

- 在单核CPU上通过时间片轮转实现任务切换

- 强调任务的分解和调度

例如:对于单核cpu处理多任务,操作系统轮流让各个任务交替执⾏,假如:软件1执⾏0.01秒,切换 到软件2,软件2执⾏0.01秒,再切换到软件3,执⾏0.01秒…… 这样反复执⾏下去, 实际上每个软 件都是交替执⾏的 . 但是,由于CPU的执⾏速度实在是太快了,表⾯上我们感觉就像这些软件都 在同时执⾏⼀样 . 这⾥需要注意单核cpu是并发的执⾏多任务的。

并发:任务数量大于CPU核心数

2、并⾏

概念:在⼀段时间内真正的同时⼀起执⾏多个任务。

- 多个任务在同一时刻真正同时执行

- 需要多核CPU支持

- 强调任务的同时执行

对于多核cpu处理多任务,操作系统会给cpu的每个内核安排⼀个执⾏的任务,多个内核是真正的 ⼀起同时执⾏多个任务。这⾥需要注意多核cpu是并⾏的执⾏多任务,始终有多个任务⼀起执⾏。

并行:任务数量小于或等于CPU核心数

3、并发与并行的区别

特性并发并行
核心定义多个任务在重叠的时间段内交替执行多个任务在同一时刻同时执行
关键思想任务切换同时执行
硬件需求单核CPU即可实现必须依赖多核CPU或多台计算机
关注点程序的设计与结构(处理多个任务的能力)程序的执行与计算(加快任务完成的速度)
主要目的提高系统的资源利用率响应能力提高系统的计算速度吞吐量
关系并发是并行的必要条件,但并发不一定并行。 并行是并发的真子集。
生活比喻一个人(单核)同时做两件事: 边看电视边回微信,大脑在快速切换。两个人(多核)同时做两件事: 一个人看电视,另一个人同时回微信。
编程模型多线程、协程、异步IO、事件循环多进程、GPU计算、分布式计算
优势使I/O密集型应用不会阻塞,最大化利用CPU时间片充分利用多核资源,大幅缩短计算密集型任务的时间
挑战线程安全、竞态条件、死锁、数据同步任务拆分、负载均衡、进程间通信、数据一致性

三、进程与多进程

1、程序中实现多任务的⽅式

在Python中,想要实现多任务可以使⽤ 多进程来完成。

2、进程的概念

进程(Process)是资源分配的最⼩单位,它是操作系统进⾏资源分配和调度运⾏的基本单位,通 俗理解:⼀个正在运⾏的程序就是⼀个进程。

例如:正在运⾏的qq , 微信等 他们都是⼀个进程。

注: ⼀个程序运⾏后⾄少有⼀个进程

- 程序在执行时的一个实例(应用程序)

- 拥有独立的内存空间和系统资源

- 进程间相互隔离,安全性高

3、多进程的作⽤

图中是⼀个⾮常简单的程序 , ⼀旦运⾏hello.py这个程序 , 按照代码的执⾏顺序 , func_a函数执⾏ 完毕后才能执⾏func_b函数 . 如果可以让func_a和func_b同时运⾏ , 显然执⾏hello.py这个程序的 效率会⼤⼤提升 .

未使用多进程

使用了多进程

4、多进程完成多任务

① 导⼊进程包

import multiprocessing

② 通过进程类创建进程对象

进程对象 = multiprocessing.Process()

③ 启动进程执⾏任务

进程对象.start()

5、通过进程类创建进程对象

进程对象 = multiprocessing.Process([group [, target=任务名 [, name]]])

参数说明:

参数名说明
target执行的目标任务名,这里指的是函数名(方法名)
name进程名,一般不用设置
group进程组,目前只能使用None

6、进程创建与启动的代码

边听音乐,边敲代码:

# 导入多进程模块,用于创建和管理进程
import multiprocessing
# 导入时间模块,用于模拟耗时操作和计时
import timedef music():"""任务函数:模拟听音乐"""for i in range(3):print('听音乐...')time.sleep(0.2)  # 模拟每次听音乐的耗时def coding():"""任务函数:模拟敲代码"""for i in range(3):print('敲代码...')time.sleep(0.2)  # 模拟每次敲代码的耗时if __name__ == '__main__':# 创建执行music函数的进程music_process = multiprocessing.Process(target=music)# 创建执行coding函数的进程coding_process = multiprocessing.Process(target=coding)# 启动两个进程music_process.start()coding_process.start()# 等待两个进程都执行完毕music_process.join()coding_process.join()print("所有任务完成!")

7、进程执⾏带有参数的任务

Process([group [, target [, name [, args [, kwargs]]]]])

参数说明:

参数名说明示例
args以元组的方式给执行任务传参,表示调用对象的位置参数args=(1, 2, 'anne')
kwargs以字典方式给执行任务传参,表示调用对象的关键字参数kwargs={'name': 'anne', 'age': 18}

 案例:args参数和kwargs参数的使⽤

# 导入多进程模块
import multiprocessing
# 导入时间模块
import timedef music(num):"""模拟听音乐的任务参数:- num: int, 音乐播放的次数该函数通过循环模拟播放音乐,每次播放后暂停0.2秒。"""for i in range(num):print('听音乐...')time.sleep(0.2)def coding(count):"""模拟编码任务参数:- count: int, 敲代码的次数该函数通过循环模拟敲代码的动作,每次敲代码后暂停0.2秒。"""for i in range(count):print('敲代码...')time.sleep(0.2)# 在主程序中启动多进程
if __name__ == '__main__':# 创建音乐进程,参数为播放音乐的次数music_process = multiprocessing.Process(target=music, args=(3,))# 创建编码进程,参数为敲代码的次数coding_process = multiprocessing.Process(target=coding, kwargs={'count': 3})# 启动音乐进程music_process.start()# 启动编码进程coding_process.start()# 打印主进程开始的信息print('主进程开始')# 使主进程暂停1秒,以模拟进程初始化或资源准备的时间time.sleep(1)# 等待音乐进程结束music_process.join()# 等待编码进程结束coding_process.join()# 打印主进程结束的信息print('主进程结束')

注意点:

1. 入口点保护:必须使用 `if __name__ == '__main__':` 保护主程序入口

2. 参数序列化:传递给进程的参数必须是可序列化的

3. 进程间通信:使用 `Queue`、`Pipe` 等机制进行进程间数据交换

4. 资源管理:及时调用 `join()` 等待进程结束,避免僵尸进程

四、线程与多线程

1、线程的概念

在Python中,想要实现多任务还可以使⽤多线程来完成。

- 进程内的执行单元(函数,class类)

- 同一进程内的线程共享内存空间(数据可以共享)

- 是CPU调度的基本单位

2、为什么使⽤多线程?

进程是分配资源的最⼩单位 , ⼀旦创建⼀个进程就会分配⼀定的资源 , 就像跟两个⼈聊QQ就需要 打开两个QQ软件⼀样是⽐较浪费资源的 .

线程是程序执⾏的最⼩单位 , 实际上进程只负责分配资源 , ⽽利⽤这些资源执⾏程序的是线程 , 也 就说进程是线程的容器 , ⼀个进程中最少有⼀个线程来负责执⾏程序 。

同时线程⾃⼰不拥有系统 资源,只需要⼀点⼉在运⾏中必不可少的资源,但它可与同属⼀个进程的其它线程共享进程所拥有 的全部资源 。这就像通过⼀个QQ软件(⼀个进程)打开两个窗⼝(两个线程)跟两个⼈聊天⼀样 , 实 现多任务的同时也节省了资源

3、多线程完成多任务

多线程完成多任务

① 导⼊线程模块

import threading

② 通过线程类创建线程对象

线程对象 = threading.Thread(target=任务名)

③ 启动线程执⾏任务

线程对象.start()

参数名说明
target执行的目标任务名,这里指的是函数名(方法名)
name线程名,一般不用设置
group线程组,目前只能使用None

线程创建与启动代码

单线程案例

# 单线程案例
import timedef music():for i in range(3):print('听音乐...')time.sleep(0.2)def coding():for i in range(3):print('敲代码...')time.sleep(0.2)if __name__ == '__main__':music()coding()

多线程案例

# 多线程案例
import time
import threadingdef music():"""模拟听音乐的任务循环三次,每次打印听音乐的状态并暂停0.2秒"""for i in range(3):print('听音乐...')time.sleep(0.2)def coding():"""模拟编码的任务循环三次,每次打印敲代码的状态并暂停0.2秒"""for i in range(3):print('敲代码...')time.sleep(0.2)if __name__ == '__main__':# 创建一个线程,用于播放音乐。通过threading.Thread类创建线程,music函数作为线程要执行的目标。music_thread = threading.Thread(target=music)# 创建一个线程,用于编码工作。同样使用threading.Thread类创建,coding函数作为线程要执行的目标。coding_thread = threading.Thread(target=coding)# 启动音乐线程和编码线程music_thread.start()coding_thread.start()# 等待音乐线程完成其任务music_thread.join()# 等待编码线程完成其任务coding_thread.join()print('程序结束')

线程执⾏带有参数的任务

参数名说明
args以元组的方式给执行任务传参
kwargs以字典方式给执行任务传参
# 导入time模块和threading模块
import time
import threadingdef music(num):"""模拟听音乐的函数参数:- num: int, 控制音乐播放的次数该函数通过循环播放音乐,并在每次播放时暂停0.2秒来模拟听音乐的行为。"""for i in range(num):print('听音乐...')time.sleep(0.2)def coding(count):"""模拟编码的函数参数:- count: int, 控制编码操作的次数该函数通过循环模拟编码行为,并在每次编码时暂停0.2秒来模拟实际编码过程。"""for i in range(count):print('敲代码...')time.sleep(0.2)# 程序入口
if __name__ == '__main__':# 创建一个线程,负责播放音乐# 参数说明:# - target: 指定要执行的函数,这里是音乐播放函数# - args: 传递给函数的参数,这里使用元组(3,)作为示例music_thread = threading.Thread(target=music, args=(3,))# 创建另一个线程,负责编码任务# 参数说明:# - target: 指定要执行的函数,这里是编码函数# - kwargs: 传递给函数的关键字参数,这里指定count为3coding_thread = threading.Thread(target=coding, kwargs={'count': 3})# 启动音乐线程和编码线程music_thread.start()coding_thread.start()# 等待音乐线程完成其任务music_thread.join()# 等待编码线程完成其任务coding_thread.join()print('程序结束')

注意点

1. GIL限制:受全局解释器锁限制,CPU密集型任务无法真正并行

2. 线程安全:共享数据时需要使用锁机制保证线程安全

3. 死锁风险:多个锁的使用需要注意死锁问题

4. 资源竞争:需要合理使用同步原语(Lock、RLock、Semaphore等)

五、协程

1 协程定义与优势

协程(Coroutine)是⽤户态的轻量级线程,通过协作式多任务实现并发。

相⽐线程,协程的切换⽆需操 作系统调度,仅需保存寄存器上下⽂,因此效率更⾼。

核⼼优势:

1. ⽆锁机制:避免多线程同步开销

2. ⾼并发:单线程内处理数千级I/O密集型任务(如⽹络请求)

3. 代码简洁:⽤同步语法写异步逻辑( async/await )

2 协程实现⽅式(以 asyncio 为核⼼)

基础语法

import asyncio# 定义一个异步协程函数
async def my_coroutine():"""一个简单的协程函数,用于演示asyncio库的基本使用。此函数没有参数和返回值。"""print("Start")await asyncio.sleep(1)  # 非阻塞式休眠print("End")# 运行协程
asyncio.run(my_coroutine())  # Python3.7+ 推荐方式

事件循环与任务创建

import asyncio# 定义一个异步任务,该任务会在指定延迟后完成
async def task(name, delay):"""异步任务函数,模拟一个需要时间完成的任务。参数:name: 任务名称,用于标识任务。delay: 延迟时间,任务完成前需要等待的时间(秒)。"""await asyncio.sleep(delay)  # 模拟任务耗时print(f"{name} completed")# 定义主协程,用于管理和执行其他协程任务
async def main():"""主协程函数,负责调度和执行多个异步任务。"""# 创建任务列表tasks = [asyncio.create_task(task("A", 2)),  # 创建任务A,延迟2秒完成asyncio.create_task(task("B", 1))   # 创建任务B,延迟1秒完成]await asyncio.gather(*tasks)  # 并发执行所有任务# 运行主协程
asyncio.run(main())

注:输出顺序:B → A(任务按完成时间排序)

3 核⼼模块与API

模块/方法作用描述
asyncio.run()启动事件循环的入口函数
asyncio.create_task()将协程包装为任务对象
asyncio.gather()并发执行多个协程
asyncio.sleep()非阻塞式等待(替代 time.sleep)
asyncio.Queue协程安全队列,用于生产者-消费者模型

4 其他协程库

1. Gevent

基于 greenlet ,通过 monkey.patch_all() ⾃动切换协程:

# 导入gevent的monkey模块,用于打补丁以支持协程
from gevent import monkey# 导入gevent模块,用于创建协程
import gevent# 为所有标准模块打上补丁,使其支持协程
# 包括socket、select、thread、time等模块的阻塞操作变为非阻塞
monkey.patch_all()# 定义一个简单的任务函数,将在协程中执行
def task():print("Gevent task")# 使用列表推导式创建3个协程任务
# gevent.spawn() 创建协程实例,每个实例执行task()函数
tasks = [gevent.spawn(task) for _ in range(3)]# 一次性等待所有协程完成
# joinall()会阻塞当前协程直到所有任务完成
gevent.joinall(tasks)

2. Greenlet ⼿动切换协程:

# 导入greenlet模块,实现轻量级协程
from greenlet import greenlet# 定义第一个协程函数
def test1():print(1)gr2.switch()  # 手动切换到gr2协程# 定义第二个协程函数
def test2():print(2)# test2执行完毕后自动回到主协程# 创建协程对象
gr1 = greenlet(test1)  # 基于test1函数创建协程
gr2 = greenlet(test2)  # 基于test2函数创建协程# 启动协程系统
gr1.switch()  # 切换到gr1协程,开始执行test1函数

注意点:

1. 异步环境:协程必须在异步环境中运行

2. await关键字:调用异步函数时必须使用 `await` 关键字

3. 阻塞操作:避免在协程中使用阻塞操作,应使用异步版本

4. 异常处理:合理处理协程中的异常,避免影响整个事件循环

5. 资源管理:正确管理协程的生命周期,及时取消不需要的任务

六、进程 vs. 线程 vs. 协程 总结对比表

进程 (Process)线程 (Thread)协程 (Coroutine)
基本定义资源分配的基本单位,
程序的一次执行实例
CPU调度的基本单位,
进程内的一个执行流
用户态的轻量级线程,
由程序员控制的协作式任务
资源开销
(独立内存空间、PCB)
中等
(共享内存,但有独立栈、TCB)
极小
(通常在KB级别,无系统开销)
切换开销
(需要切换内存空间,CPU上下文)
中等
(需切换CPU上下文,由OS内核调度)
极小
(用户态切换,无内核参与)
数据共享复杂
(需要IPC:队列、管道、共享内存等)
简单
(共享进程内存,但需注意线程安全)
极简单
(共享所有上下文变量)
并发能力利用多核CPU
真正并行
利用多核CPU
真正并行
单线程内并发
协作式并发
创建数量少(通常几十到上百个)中(通常几百到上千个)极多(可轻松创建数万甚至百万个)
隔离性/安全性
(一个进程崩溃不影响其他进程)

(一个线程崩溃可能导致整个进程崩溃)

(一个协程异常通常不影响其他协程)
控制者操作系统内核操作系统内核程序员(用户态)
适用场景CPU密集型任务、
需要高安全隔离的任务
I/O密集型任务、
需要共享数据的并发任务
高并发I/O密集型任务、
大量网络连接、异步编程
编程复杂度高(需处理进程间通信)中(需处理线程同步和锁)低(异步编程模型,逻辑清晰)
Python模块multiprocessingthreadingasyncio
全局解释器锁(GIL)影响无影响(每个进程有独立GIL)受限制(同一进程线程只能有一个执行)受限制(在同一个线程内运行)


文章转载自:

http://1I8PEYSa.rhchr.cn
http://3Z0JAuYF.rhchr.cn
http://h6hPNZmf.rhchr.cn
http://iVmAN13H.rhchr.cn
http://R90iBAge.rhchr.cn
http://5obtKJBp.rhchr.cn
http://9np1D7yh.rhchr.cn
http://o9qO0mxH.rhchr.cn
http://tepfvXl8.rhchr.cn
http://bMqtTXVW.rhchr.cn
http://XbIqichR.rhchr.cn
http://pqJSfAcW.rhchr.cn
http://1QodByQ9.rhchr.cn
http://UFNwDtHW.rhchr.cn
http://NtEcGuw1.rhchr.cn
http://pk3XfskH.rhchr.cn
http://kpXPUL8k.rhchr.cn
http://ZxjMYaKe.rhchr.cn
http://8Qg9eGZe.rhchr.cn
http://lW0ccA7K.rhchr.cn
http://u94zermS.rhchr.cn
http://6LM3qI58.rhchr.cn
http://8SZVwLn3.rhchr.cn
http://tpaq7bFl.rhchr.cn
http://bHGElxov.rhchr.cn
http://iA1Vl6eh.rhchr.cn
http://Pr6Tvt16.rhchr.cn
http://ZFjLK7ve.rhchr.cn
http://mb3XkOpy.rhchr.cn
http://Qtaj6ehS.rhchr.cn
http://www.dtcms.com/a/372454.html

相关文章:

  • [特殊字符] 基于Qwen Coder的上下文工程编程框架,为AI辅助开发提供标准化流程
  • 升级PyCharm后,解释器配置正确、模块安装正确,但脚本就是找不到
  • 实现自己的AI视频监控系统-第四章-基于langchain的AI大模型与智能体应用1
  • 155. 最小栈
  • 【开题答辩全过程】以 基于微信小程序校园综合服务平台的设计与实现为例,包含答辩的问题和答案
  • 001-Pandas的数据结构
  • QProxyStyle类中的drawPrimitive函数的作用
  • LangChain4j RAG流程全解析
  • 【应用案例】AI 给医用过滤器 “找茬”:3 大难点 + 全流程解决方案
  • VBA之Word应用第四章第二节:段落集合Paragraphs对象(二)
  • Git 工作流与分支管理实战:rebase vs merge 对比、冲突解决、规范 Commit Message 与主干稳定性最佳实践
  • 《沈南鹏传 - 做最擅长的事》(上篇)天才的成长之路-读书笔记
  • C++笔记之同步信号量、互斥信号量与PV操作再探(含软考题目)
  • C语言运算符
  • 知识库AI问答重新设计,新增文档引用功能,zyplayer-doc 2.5.3 发布啦!
  • 从Sonnet到Opus:一次解决RAG知识库流式输出难题的探索
  • 【Javaweb学习|实训总结|Week1】html基础,CSS(选择器、常用样式、盒子模型、弹性盒布局、CSS定位、动画),js(基本类型、运算符典例)
  • PPP协议概念及流程
  • pytorch的两大法宝函数
  • JAVA:IO流非文本形式文件拷贝
  • Tesseract,Tika 解析文件内容保存到ES
  • Redis中的Set数据类型
  • 2025算法八股——深度学习——优化器小结
  • Hash桶的讲解
  • [SWERC 2020] Safe Distance题解
  • 【.Net技术栈梳理】01-核心框架与运行时(CLR)
  • 《十字军东征》游戏出现0xc0000022报错的解决办法
  • 个人博客系统_测试报告
  • 第四项修炼:多元权衡——告别“单点最优”,在矛盾中编织和谐
  • Claude 4深度解析:AI编程新王者,双模型重塑行业标杆