python 多任务
创始人
2025-05-30 23:43:26

一些概念

1.多任务

简单地说,就是同时可以运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务。

2.并行

指的是任务数小于等于cpu核数,在一段时间内真正的同时一起执行多个任务。每个核同时处理不同的任务,即任务真的是同时执行的

3.并发

在一段时间内交替去执行多个任务,对于单核CPU处理多任务,操作系统轮流让各个任务在cpu上交替执行(多个任务看起来是同时运行的

真正的"并行"只能在多核CPU上实现,现实中由于任务数量远远多于CPU的核心数量,所以基本上都是“并发”。 操作系统会自动把很多任务轮流调度到每个核心上执行。

4.串行

多个任务时,运行完一个再运行下一个

python实现多任务的方法

1.多线程

线程是执行程序的最小单位

使用threading模块

import threading
import timedef say_sorry():print("亲爱的,我错了,我能吃饭了吗?")time.sleep(1)for i in range(5):t = threading.Thread(target=say_sorry)t.start()  # 启动线程,即让线程开始执行

1.1同时执行多个不同的任务:

1.如果在一个程序中需要有多个任务一起执行,可以将每个任务单独放到一个函数中
2.使用threading.Thread创建一个对象,注意实参target需要指定为刚刚定义的函数名(不要写上小括号,那表示调用函数了)
3.调用threading.Thread返回的对象中的start方法(会让这个线程开始运行)

import threading
from time import sleep, ctimedef sing():for i in range(3):print("正在唱歌...%d" % i)sleep(1)def dance():for i in range(3):print("正在跳舞...%d" % i)sleep(1)print('---开始---:%s' % ctime())
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
#sleep(5)  # 屏蔽此行代码,试试看,程序是否会立马结束?
print('---结束---:%s' % ctime())

1.2多线程执行的顺序不确定

当python程序中有多个任务需要被执行时,这些任务需要等待操作系统的调度(即操作系统安排接下来要执行哪个任务),因为每次运行程序时的环境(例如上次运行时 除了这个python程序之外还有QQ、微信在运行,而这次运行时没有QQ只有微信在运行都会影响操作系统的调度策略)不一样,所以多次运行同一个python程序时任务执行的先后顺序是不同的

1.3多线程-共享全局变量

1.在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
2.缺点是:线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)

1.4互斥锁

  1. 为什么要用互斥锁?
    当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
    线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。

  2. 互斥锁的作用
    互斥锁为资源引入一个状态:锁定/非锁定
    某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

threading模块中定义了Lock类,可以方便的使用:

# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()

注意:
如果这个锁之前是没有上锁的,那么acquire不会堵塞(堵塞:理解为程序卡在这里等待某个条件满足)
如果在调用acquire对这个锁上锁之前 它已经被 其他线程上了锁,那么此时acquire会堵塞,直到这个锁被解锁为止

锁的好处:
确保了某段关键代码同时只能由一个线程从头到尾完整地执行

锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁

2.多进程

进程(Process) 是资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位,
通俗理解: 一个正在运行的程序就是一个进程。例如:正在运行的qq,微信等,他们都是一个进程。
注意:一个正在运行的程序才叫进程,而没有运行的程序,只能叫程序,不能叫进程。同时,一个程序可以有一个或者多个进程。

多进程的作用:
同时执行多个函数,提升效率

进程注意事项:
主进程会等待所有的子进程完成才结束
#(2)设置守护主进程:每一个子进程都守护主进程,当主进程结束了之后,子进程直接结束,也就是被销毁。

2.1python多进程的实现

multiprocessing模块是跨平台版本的多进程模块,提供了一个Process类来创建一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情

通过额外创建一个进程,可以实现多任务
使用进程实现多任务的流程:
创建一个Process对象,且在创建时通过target指定一个函数的引用
当调用start时,会真正的创建一个子进程

from multiprocessing import Process
import timedef test():"""子进程单独执行的代码"""while True:print('---test---')time.sleep(1)if __name__ == '__main__':p=Process(target=test)p.start()# 主进程单独执行的代码while True:print('---main---')time.sleep(1)

2.2进程不共享全局变量

进程间是相互独立的,数据不共享,但有时需要数据共享,就需要进程间通信(IPC)

2.3进程间通信-Queue

可以使用multiprocessing模块的Queue实现多进程之间的数据传递

from multiprocessing import Queue
q = Queue(3)  # 初始化一个Queue对象,最多可接收三条put消息
q.put("消息1")
q.put("消息2")
print(q.full())  # False
q.put("消息3")
print(q.full())  # True# 因为消息列队已满,所以会导致下面的try都会抛出异常,
# 第一个try会等待2秒后再抛出异常
# 第二个Try会立刻抛出异常
try:q.put("消息4", True, 2)
except:print("消息列队已满,现有消息数量:%s" % q.qsize())try:q.put_nowait("消息4")
except:print("消息列队已满,现有消息数量:%s" % q.qsize())# 推荐的方式,先判断消息列队是否已满,再写入
if not q.full():q.put_nowait("消息4")# 读取消息时,先判断消息列队是否为空,再读取
if not q.empty():for i in range(q.qsize()):print(q.get_nowait())

3.协程

协程,又称微线程

协程和线程差异
在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。

简单实现协程

import timedef work1():while True:print("----work1---")yieldtime.sleep(0.5)def work2():while True:print("----work2---")yieldtime.sleep(0.5)def main():w1 = work1()w2 = work2()while True:next(w1)next(w2)if __name__ == "__main__":main()

4.线程、进程对比

4.1关系对比

1.线程是依附在进程里的,没有进程就没有线程
2.一个进程默认提供一条线程,进程可以创建多个线程

4.2区别对比

1.创建进程的资源开销比创建线程的资源开销要大
2.进程是操作系统资源分配的进本单位,线程是cpu调度的基本单位(程序执行的最小单位)
3.线程不能独立执行,必须依附在进程中

4.3优缺点

1.进程优点:可以用多核
缺点:资源开销大

2.线程优点:资源开销小
缺点:不能使用多核

4.4多线程的优点:

无需跨进程边界;
程序逻辑和控制方式简单;
所有线程可以直接共享内存和变量等;
线程方式消耗的总资源比进程方式好;

4.5多线程缺点:

每个线程与主程序共用地址空间,受限于2GB地址空间;
线程之间的同步和加锁控制比较麻烦;
一个线程的崩溃可能影响到整个程序的稳定性;
到达一定的线程数程度后,即使再增加CPU也无法提高性能,例如Windows
Server
2003,大约是1500个左右的线程数就快到极限了(线程堆栈设定为1M),如果设定线程堆栈为2M,还达不到1500个线程总数;
线程能够提高的总性能有限,而且线程多了之后,线程本身的调度也是一个麻烦事儿,需要消耗较多的CPU

4.6 多进程优点:

每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系;
通过增加CPU,就可以容易扩充性能;
可以尽量减少线程加锁 / 解锁的影响,极大提高性能,就算是线程运行的模块算法效率低也没关系;
每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限非常大

4.7多线程缺点:

逻辑控制复杂,需要和主程序交互;
需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算
多进程调度开销比较大;
最好是多进程和多线程结合,即根据实际的需要,每个CPU开启一个子进程,这个子进程开启多线程可以为若干同类型的数据进行处理。当然你也可以利用多线程 + 多CPU + 轮询方式来解决问题……

补充

GIL 全局解释器锁
python有了GIL,为什么还有线程锁(互斥锁)?
GIL是限制同一个进程中只有一个线程进入Python解释器。。。。。
而线程锁是由于在线程进行数据操作时保证数据操作的安全性(同一个进程中线程之间可以共用信息,如果同时对数据进行操作,则会出现公共数据错误)
其实线程锁完全可以替代GIL,但是Python的后续功能模块都是加在GIL基础上的,所以无法更改或去掉GIL,这就是Python语言最大的bug…只能用多进程或协程改善,或者直接用其他语言写这部分

相关内容

热门资讯

Mysql常用数据类型总结 整形 枚举类型ENUE整形       TINYINT,SMALLINT,MEDIUMINT,IN...
【flink sql】创建表 flink sql创建表语法 CREATE TABLE [IF NOT EXISTS] [catal...
python opencv 保... 👨‍💻个人简介: 深度学习图像领域工作者 dz...
Pytorch深度学习实战3-... 目录1 数据集Dataset2 数据加载DataLoader3 常用预处理方法4 模型处理5 实例&...
自定义类型的超详细讲解ᵎᵎ了解...   目录 1.结构体的声明 1.1基础知识 1.2结构体的声明 1.3结构体的特殊声明  1.4结构...
Docker等容器技术如何与移... 移动应用程序的开发面临着很多挑战,包括开发环境的设置、测试的困难、部署的复杂性等。由于...
【微服务】—— Nacos安装... 文章目录1. Windows安装1.1 下载安装包1.2 解压1.3 端口配置1.4 启动1.5 访...
【OpenGL】 为了理解这个函数我们需要先学习一些OpenGL的内容 OpenGL可视化 https://g...
hjr-详细说一下Redis集... Redis作用 缓存 一般我们用Redis做缓存,热点数据 击穿:访问到...
【蓝桥杯】 C++ 数字三角形... 文章目录题目描述输入描述输出描述实现代码解题思路注意点知识点 题目描述 上图给出了一个数字三角形。从...
VR全景展会丨探索未来,重塑现... 随着科技的不断发展,虚拟现实(VR)技术逐渐成为一个重要的...
C++数据类型 目录 C++基础数据类型 指针 指针类型 指针赋值 引用 参考:《深...
超实用!!! 三分钟将你的项目... 文章目录前言一、在项目中新增配置二、配置github page setting?三、如...
数据结构---队列 专栏:数据结构 个人主页:HaiFan. 专栏简介:这里是...
数字操作方法 系列文章目录 前端系列文章——传送门 JavaScript系列文章——传送门 文章目录系列文章目录...
Cartesi 2023 年 ... 查看 Cartesi Machine、Cartesi Rollups 和 Noether 的更新正在...
JavaWeb——jsp概述入... JSP定义:  在如下一个jsp文件里面有如下的代码  <%@ page content...
一切喜怒哀乐都来自于你的认知 01 有个学子,准备出国,父母请来清华的教授宁向东。请问教授࿱...
JAVA并发编程——synch... 引言         Java语言为了解决并发编程中存在的原子性、可见性和有序性问题,...
git学习----3.21 未... 文章目录前言Git :一个分布式版本控制工具目标一、概述1.1 开发中的实际场景1.2...
Qt优秀开源项目之十七:QtP... QtPromise是Promises/A+规范的Qt/C++实现。该规范的译...
【前端八股文】JavaScri... 文章目录Set概念与arr的比较属性和方法并集、交集、差集Map概念属性和方法String用索引值和...
海康硬盘录像机接入RTSP/o... EasyNVR安防视频云服务平台可支持设备通过RTSP/Onvif协议接入平台,能提供...
在混合劳动力时代如何避免网络安... 在混合劳动力时代如何避免安全网络风险 三年多来,混合工作一直是工作生活中不可或缺的一...
2023还不懂Jmeter接口... 这里介绍的Jmeter接口测试的的实战,如果文章内容没遇看懂的话,我这边...
基于4G/5G弱网聚合的多链路... 基于4G/5G多卡聚合(弱网聚合)的智能融合通信设备技术亮点 增强带宽提供可靠连接 通过将多个有线和...
如何使用Synplify综合v... 文章目录使用Synplify综合的好处synplify的教程方法1(无效)...
2023年全国最新高校辅导员精... 百分百题库提供高校辅导员考试试题、辅导员考试预测题、高校辅导员考试真题、辅导员证考试题库等ÿ...
2022年18个值得期待的Le... 有数百个独特的LearnDash附加组件,您可能很难选择您的LearnDash LMS...
【java基础】Stream流... 文章目录基本介绍流的创建流的各种常见操作forEach方法filter方法map方法peek方法fl...