python多任务编程
文章目录
- 进程 (Process)
- 多进程编程
- multiprocessing 模块创建进程
- 创建自定义进程类
- 进程池技术
- 进程间通信 (IPC)
- 管道通信 Pipe
- 消息队列
- 共享内存
- 信号通信
- 信号量(信号灯)
- 线程
- 线程同步互斥方法
- 多线程并发
意义 : 充分利用计算机的资源提高程序的运行效率
定义 : 通过应用程序利用计算机的多个核心达到同时执行多个任务的目的,一次提高计算机运行效率。
实施方案 : 多进程 多线程
并行 : 多个计算机核心在同时处理多个任务,这时多个任务间是并行关系。
并发 : 同时处理多个任务,内核在多个任务间不断的切换,达到好像都在处理运行的效果。但实际一个时间点内核只能处理其中一个任务。
进程 (Process)
定义 : 程序在计算机中的一次运行过程
程序 : 是一个可执行的文件,是静态的占有磁盘空间,不占有计算机的运行资源
进程 : 进程是一个动态过程的描述,占有计算机的资源,有一定的生命周期
- 同一个程序的不同运行过程是不同的进程,占用资源和生命周期都不一样。
进程的创建流程
1.用户空间通过运行程序或者调用接口发起创建进程
2.操作系统接受用户请求,开始创建进程
3.操作系统分配计算机资源,确定进程状态,开辟进程空间等工作
4.操作系统将创建好的进程提供给应用程序使用
cpu时间片
如果一个进程占有计算机核心,我们称为改进程占有计算机cpu时间片。
- 多个任务之间是争夺cpu的关系
- 谁占有cpu最终是操作系统决定
PCB (进程控制块)
在内存中开辟的一块空间,用来记录进程的信息
- 进程控制块是操作系统查找识别进程的标志
进程信息 : ps -aux
PID(process ID) : 在操作系统中每个进程都有一个唯一的ID号用来区别于其他进程。ID号由操作系统自动分配,是一个大于0的整数
父子进程 : 在系统中除了初始化进程,每一个进程都有一个父进程,可能有0个或者多个子进程。由此形成父子进程关系。
查看进程树 : pstree
查看父进程PID: ps -ajx
进程的状态
三态
* 就绪态 : 进程具备执行条件,等待系统分配资源
* 运行态 : 进程占有cpu处于运行状态
* 等待态 : 进程暂时不具备执行条件,阻塞等待满 足条件后再执行
五态 (三态基础上增加新建态,终止态)
* 新建态 : 创建一个新的进程,获取资源的过程
* 终止态 : 进程执行结束,资源释放回收的过程
ps -aux —> STAT
S 等待态 (可中断等待)
D 等待态 (不可中断等待)
T 等待态 (暂停状态)
R 运行态 (包含就绪态)
Z 僵尸进程
< 高优先级进程
N 优先级较低
l 有子进程的
s 会话组组长
- 前台进程
进程优先级
作用 : 决定了一个进程的执行权限和占有资源的优先程度
查看进程优先级
top 动态查看系统中的进程信息, 用<>翻页
取值范围 -20 – 19 -20优先级最高
使用指定的优先级运行程序
nice : 指定运行的优先级
e.g. nice -9 ./while.py 以优先级9运行nice --9 ./while.py 以-9优先级运行
进程特征
- 进程之间运行互不影响 各自独立运行
- 进程是操作系统资源分配的最小单位
- 每个进程空间独立,各自占有一定的虚拟内存
要求 :
- 什么是进程,进程和程序的区别
- 了解进程特征
- 清楚进程每种状态,以及状态之间的转换关系
多进程编程
import os pid = os.fork()
功能 : 创建新的进程
参数 : 无
返回值: 失败返回一个负数
成功 : 在原有进程中返回新的进程的PID号,在新的进程中返回0
- 子进程会复制父进程全部代码段,包括fork之前产生的内存空间
- 子进程从fork的下一句开始执行,与父进程互不干扰
- 父子进程的执行顺序是不一定的,父子进程公用一个终端显示
- 父子进程通常会根据fork返回值得差异选择执行不同的代码。所以if结构几乎是fork的固定搭配
- 父子进程空间独立,操作的都是本空间的内容,互不影响
- 子进程也有自己的特性,比如PID号,PCB,命令集等
进程相关函数
获取进程PID
os.getpid()
功能 : 获取当前进程的进程号
返回值 : 返回进程号
os.getppid()
功能 : 获取当前进程父进程的PID号
返回值 : 返回进程号
进程退出
os._exit(status)
功能 : 进程退出
参数 : 进程的退出状态
sys.exit([status])
功能 : 进程退出
参数 : 数字表示退出状态,不写默认为0
字符串,表示退出时打印的内容
- sys.exit 可以通过捕获 SystemExit异常阻止退出
孤儿进程: 父进程先于子进程退出,此时子进程就称为孤儿进程。
- 孤儿进程会被操作系统指定的进程收养,系统进程就成为孤儿进程的新的父进程
僵尸进程: 子进程先于父进程退出,但是父进程没有处理子进程的退出状态,此时子进程就会成为僵尸进程。
- 僵尸进程会存留少量PCB信息在内存中,大量的僵尸进程会消耗系统资源,应该避免僵尸进程产生
如何避免僵尸进程产生
* 处理子进程退出状态
pid,status = os.wait()
功能 :在父进程中阻塞等待处理子进程退出
返回值: pid 退出的子进程的PID号
status 获取子进程退出状态
pid,status = os.waitpid(pid,option)
功能 :在父进程中阻塞等待处理子进程退出
参数 : pid -1 表示等待任意子进程退出>0 表示等待对应PID号的子进程退出option 0 表示阻塞等待WNOHANG 表示非阻塞返回值: pid 退出的子进程的PID号status 获取子进程退出状态waitpid(-1,0) ===> wait()* 让父进程先退出1. 父进程创建子进程等待子进程退出2. 子进程创建二级子进程后立即退出3. 二级子进程称为孤儿,和原来的父进程各自执行事件
multiprocessing 模块创建进程
- 需要将要执行的事情封装为函数
- 使用multiprocessing模块中Process类创建进程对象
- 通过对象属性设置和Process的初始化函数对进程进行设置,绑定要执行的函数
- 启动进程,会自动执行进程绑定的函数
- 完成进程的回收
Process()
功能 : 创建进程对象
参数 : name 进程名称 Process-1target 绑定函数 args 元组 给target函数按照位置传参kwargs 字典 给target函数按照键值对传参p.start()
功能:启动进程
* target函数会自动执行,此时进程真正被创建p.join([timeout])
功能 : 阻塞等待回收子进程
参数 : 超时时间* 使用multiprocessing创建子进程,同样子进程复制父进程的全部代码段,
* 父子进程各自执行互不影响,父子进程有各自的运行空间* 如果不使用join回收子进程则子进程退出后会成为僵尸进程
* 使用multiprocessing创建子进程往往父进程只是用来创建进程回收进程Process进程对象属性p.start()
p.join()p.is_alive()
判断进程生命周期状态,处于生命周期得到True否则返回Falsep.name 进程名称 默认为Process-1
p.pid 进程的PID号p.daemon
默认状态False 主进程退出不会影响子进程执行
如果设置为True 则子进程会随着主进程结束而结束* 要在start前设置
* 一般不和join一起使用
创建自定义进程类
- 继承Process
- 编写自己的__init__ ,同时加载父类init方法
- 重写run方法,可以通过生成的对象调用start自动运行
优点 : 可以使用计算机多核,进行任务的并发执行,提高执行效率空间独立,数据安全 运行不受其他进程影响,创建方便
缺点 : 进程的创建和删除消耗的系统资源较多
进程池技术
产生原因 : 如果有大量任务需要多进程完成,则可能需要频繁的创建删除进程,给进算计带来较多的资源消耗。
原理 : 创建适当的进程放入进程池,用来处理待处理事件,处理完毕后进程不销毁,仍然在进程池中等待处理其他事件。 进程的复用降低了资源的消耗
使用方法
- 创建进程池,在池内放入适当的进程
- 将事件加入到进程池等待队列
- 不断取进程执行事件,直到所有事件执行完毕
- 关闭进程池,回收进程
from multipeocessing import PoolPool(processes)
功能 : 创建进程池对象
参数 :表示进程池中有多少进程pool.apply_async(func,args,kwds)
功能 : 将事件放入到进程池队列
参数 : func 事件函数args 以元组形式给func传参kwds 以字典形式给func传参
返回值 : 返回一个代表进程池事件的对象pool.apply(func,args,kwds)
功能 : 将事件放入到进程池队列
参数 : func 事件函数args 以元组形式给func传参kwds 以字典形式给func传参pool.close()
功能: 关闭进程池pool.join()
功能:回收进程池pool.map(func,iter)
功能: 将要做的时间放入进程池
参数: func 要执行的函数iter 迭代对象
返回值 : 返回事件函数的返回值列表
进程间通信 (IPC)
原因 : 进程空间相对独立,资源无法相互获取,此时在不同进程间通信需要专门方法。
进程间通信方法 : 管道 消息队列 共享内存 信号
信号量 套接字
管道通信 Pipe
通信原理 : 在内存中开辟管道空间,生成管道操作对象,多个进程使用"同一个"管道对象进行操作即可实现通信
multiprocessing ---》 Pipefd1,fd2 = Pipe(duplex = True)
功能 : 创建管道
参数 : 默认表示双向管道如果设置为False则为单向管道
返回值 : 表示管道的两端如果是双向管道 都可以读写如果是单向管道 则fd1只读 fd2只写fd.recv()
功能 : 从管道读取信息
返回值: 读取到的内容* 如果管道为空则阻塞fd.send(data)
功能:向管道写入内容
参数: 要写入的内容
* 可以发送python数据类型
消息队列
队列 : 先进先出
通信原理 : 在内存中建立队列数据结构模型。多个进程都可以通过队列存入内容,取出内容的顺序和存入顺序保持一致
创建队列
q = Queue(maxsize = 0)
功能 : 创建消息队列
参数 : 表示最多存放多少消息。默认表示根据内存分配存 储
返回值 : 队列对象q.put(data,[block,timeout])
功能: 向队列存储消息
参数 :data 要存的内容block 默认队列满时会阻塞,设置为False则非阻塞timeout 超时时间data = q.get([block,timeout])
功能:获取队列消息
参数:block 默认队列空时会阻塞,设置为False则非阻塞timeout 超时时间
返回值 : 返回取出的内容q.full() 判断队列是否为满
q.empty() 判断队列是否为空
q.qsize() 判断队列中消息数量
q.close() 关闭队列
共享内存
通信原理:在内存空开辟一块空间,对多个进程可见,进程可以写入输入,但是每次写入的内容会覆盖之前的内容。
obj = Value(ctype,obj)
功能 : 开辟共享内存空间
参数 : ctype 要存储的数据类型obj 共享内存的初始化数据
返回 :共享内存对象obj.value 即为共享内存值,对其修改即修改共享内存obj = Array(ctype,obj)
功能 : 开辟共享内存空间
参数 : ctype 要存储的数据格式obj 初始化存入的内容 比如列表,字符串如果是整数则表示开辟空间的个数
返回值 : 返回共享内存对象* 可以通过遍历过户每个元素的值e.g. [1,2,3] ---> obj[1] == 2* 如果存入的是字符串obj.value 表示字符串的首地址
管道 消息队列 共享内存
开辟空间 内存 内存 内存读写方式 两端读写 先进先出 覆盖之前内容双向/单向效率 一般 一般 较高应用 多用于父 广泛灵活 需要注意子进程 进行互斥操作
信号通信
一个进程向另一个进程发送一个信号来传递某种讯息,接受者根据接收到的信号进行相应的行为
kill -l 查看系统信号
kill -sig PID 向一个进程发送信号
关于信号
信号名称 信号含义 默认处理方法
SIGHUP 连接断开
SIGINT CTRU-C
SIGQUIT CTRU-
SIGTSTP CTRL-Z
SIGKILL 终止一个进程
SIGSTOP 暂停一个进程
SIGALRM 时钟信号
SIGCHLD 子进程状态改变时给父进程发出
python 发送信号signal os.kill(pid,sig)
功能: 发送信号
参数: pid 目标进程sig 要发送的信号
import signalsignal.alarm(sec)
功能 : 向自身发送时钟信号 --》 SIGALRM
参数 : sec 时钟时间* 进程中只能有一个时钟,第二个会覆盖第一个时间同步执行 : 按照顺序逐句执行,一步完成再做下一步
异步执行 : 在执行过程中利用内核记录延迟发生或者准备 处理的事件。这样不影响应用层的持续执行。 当事件发生时再由内核告知应用层处理* 信号是唯一的异步通信方法signal.pause()
功能:阻塞等待接收一个信号signal.signal(signum,handler)
功能: 处理信号
参数: signum 要处理的信号handler 信号的处理方法 SIG_DFL 表示使用默认的方法处理SIG_IGN 表示忽略这个信号func 传入一个函数表示用指定函数处理def func(sig,frame)sig: 捕获到的信号frame : 信号对象
信号量(信号灯)
原理 : 给定一个数量,对多个进程可见,且多个进程都可以操作。进程通过对数量多少的判断执行各自的行为。
multiprocessing --》 Semaphore()sem = Semaphore(num)
功能: 创建信号量
参数: 信号量初始值
返回: 信号量对象sem.get_value() 获取信号量值
sem.acquire() 将信号量减1 当信号量为0会阻塞
sem.release() 将信号量加1进程的同步互斥临界资源 :多个进程或者线程都能够操作的共享资源
临界区 : 操作临界资源的代码段同步 : 同步是一种合作关系,为完成某个任务,多进程或者多线程之间形成一种协调,按照约定或条件执行操作临界资源。互斥 : 互斥是一种制约关系,当一个进程或者线程使用临界资源时进行上锁处理,当另一个进程使用时会阻塞等待,直到解锁后才能继续使用。Event 事件multiprocessing --》 Event创建事件对象
e = Event()设置事件阻塞
e.wait([timeout])事件设置 当事件被设置后e.wait()不再阻塞
e.set()清除设置 当事件设置被clear后 e.wait又会阻塞
e.clear()事件状态判断
e.is_set()Lock 锁创建对象
lock = Lock() lock.acquire() 上锁 如果锁已经是上锁状态调用此函数会阻塞lock.release() 解锁with lock: 上锁........解锁
线程
线程也是一种多任务编程方法,可以利用计算机多核资源完成程序的并发执行。线程又被称为轻量级的进程。
线程特征
- 线程计算机多核分配的最小单位
- 一个进程可以包含多个线程
- 线程也是一个运行的过程,消耗计算机资源,多个线程共享进程的资源和空间
- 线程的创建删除消耗的资源都要远远小于进程
- 多个线程之间执行互不干扰
- 线程也有自己的特有属性,比如指令集 ID
threading 模块创建线程threading.Thread()
功能 : 创建线程对象
参数 :name 线程名称 默认 Thread-1 target 线程函数 args 元组 给线程函数位置传参kwargs 字典 给线程函数键值传参t.start() 启动线程 自动运行线程函数
t.join([timeout]) 回收线程线程对象属性t.is_alive() 查看线程状态
t.name 线程名称
t.setName() 设置线程名称
t.getName() 获取线程名称
threading.currentThread() 获取当前线程对象t.daemon 属性
默认情况主线程退出不会影响分支线程执行
如果设置为True 则分支线程随主线程退出设置方法:
t.daenon = True
t.setDaemon(True)判断属性值
t.isDaemon()* 要在start前设置,不会和join同用创建自己的线程类
步骤:
1.继承Thread
2.加载Thread中的__init__
3.重写run方法
线程通信
通信方法: 多个线程共享进程的空间,所以线程间通 信使用全局变量完成。注意事项: 线程间使用全局变量往往要同步互斥机制 保证通信安全
线程同步互斥方法
线程的event
e = threading.Event() 创建事件对象
e.wait([timeout]) 如果e为设置状态则不阻塞否则阻塞
e.set() 将e变为设置状态
e.clear() 清除设置线程锁
lock = threading.Lock() 创建锁对象
lock.acquire() 上锁
lock.release() 解锁* 也可以通过with上锁,上锁状态调用acquire会阻塞
多线程并发
threading 的多线程并发
对比多进程并发:
* 消耗资源较少
* 线程应该更注意共享资源的操作
* 在python中应该注意GIL问题,网络延迟较高,线程并 发也是一种可行的办法
实现步骤
1. 创建套接字,绑定监听
2. 接收客户端请求,创建新的线程
3. 主线程继续接收其他客户端连接
4. 分支线程启动对应的函数处理客户端请求
5. 当客户端断开,则分支线程结束
cookie
import tracebacktraceback.print_exc()
功能 : 更详细的打印异常信息集成模块的使用
python3 socketserver功能 : 通过模块的不同类的组合完成多进程/多线程 的 tcp/udp的并发StreamRequestHandler 处理tcp套接字请求
DatagramRequestHandler 处理udp套接字请求TCPServer 创建tcp server
UDPServer 创建udp serverForkingMixIn 创建多进程
ForkingTCPServer --> ForkingMinIn + TCPServer
ForkingUDPServer --> ForkingMinIn + UDPServerThreadingMixIn 创建多线程
ThreadingTCPServer --> ThreadingMinIn + TCPServer
ThreadingUDPServer --> ThreadingMinIn + UDPServer
HTTPServer V2.0
- 接收客户端请求
- 解析客户端请求
- 组织数据,形成HTTP response
- 将数据发送给客户端
升级
- 采用多线程并发接收多个客户端请求
- 基本的请求解析,根据请求返回相应的内容
- 除了可以请求静态网页,也可以请求简单的数据
- 将功能封装在一个类中
技术点 :
- socket tcp 套接字
- http协议的请求响应格式
- 线程并发的创建方法
- 类的基本使用
协程基础
定义 : 纤程,微线程。协程的本质是一个单线程程序,所以协程不能够使用计算机多核资源。
作用 : 能够高效的完成并发任务, 占用较少的资源。因 此协程的并发量较高
原理 : 通过记录应用层的上下文栈区,实现在运行中进行上下文跳转,达到可以选择性地运行想要运行的部分,以此提高程序的运行效率。
优点 : 消耗资源少
无需切换开销
无需同步互斥
IO并发性好
缺点 : 无法利用计算机多核
yield —》 协程实现的基本关键字
greenletgreenlet.greenlet() 生成协程对象
gr.switch() 选择要执行的协程事件gevent1. 将协程事件封装为函数
2. 生成协程对象gevent.spawn(func,argv)功能 : 生成协程对象参数 : func 协程函数argv 给协程函数传参返回值 : 返回协程对象3.回收协程gevent.joinall()功能 : 回收协程参数: 列表 将要回收的协程放入列表gevent.sleep(n)功能: 设置协程阻塞,让协程跳转参数: n 阻塞时间from gevent import monkey
monkey.patch_all()
功能: 修改套接字的IO阻塞行为* 必须在socket导入之前使用
python多任务编程相关推荐
- python多任务编程_python线程的多任务编程
多任务 多任务介绍 对于人来说,一边听歌,一边跳舞就是多任务. 对于电脑,简单的说,同一时间执行多个程序处理数据叫做多任务 多任务理解 单核CPU 单核cpu在处理多任务的时候是根据时间片轮转的方式进 ...
- python高级编程-网络编程、多任务
python高级编程 1 IP地址 用来在网络中标记一台电脑:在本地局域网上是唯一的. 2 端口 一个程序需要收发网络数据,就需要端口号. 3 socket 创建socket # 创建tcp sock ...
- Python网络编程(线程通信、GIL、服务器模型)
什么是进程.进程的概念? 进程的概念主要有两点: 第一,进程是一个实体.每一个进程都有它自己的地址空间, 一般情况下,包括文本区域(text region).数据区域(data region)和堆栈( ...
- python网络编程基础(线程与进程、并行与并发、同步与异步、阻塞与非阻塞、CPU密集型与IO密集型)...
python网络编程基础(线程与进程.并行与并发.同步与异步.阻塞与非阻塞.CPU密集型与IO密集型) 目录 线程与进程并行与并发同步与异步阻塞与非阻塞CPU密集型与IO密集型 线程与进程 进程 前言 ...
- Python并发编程理论篇
Python并发编程理论篇 前言 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例的人,却不知道如何去学习更加高深的知识 ...
- python核心编程--笔记(不定时跟新)(转)
的解释器options: 1.1 –d 提供调试输出 1.2 –O 生成优化的字节码(生成.pyo文件) 1.3 –S 不导入site模块以在启动时查找python路径 1.4 –v ...
- python编程入门-Python 异步编程入门
本文是写给 JavaScript 程序员的 Python 教程. Python 的异步编程,其他人可能觉得很难,但是 JavaScript 程序员应该特别容易理解,因为两者的概念和语法类似.JavaS ...
- python多进程编程_【玩树莓】编程篇(八)Python多线程、多进程编程
1.多任务编程 除了计算性能和图形显示以外,树莓派区别于Arduino的一大特点就是运行多任务操作系统.通过多任务系统用户可以同时执行多个互相独立的程序(任务),来完成不同的操作. 利用Python的 ...
- Python -- 网络编程
目录 1.网络通信的概念 2.IP地址 3.网络通信方式 3.1 直接通信 3.2 使用集线通信 3.3 通用交换机通信 3.4 使用路由器连接多个网络 3.5 复杂的通信过程 4.端口 4.1 端口 ...
最新文章
- 19.Remove Nth Node From End of List
- [ZCCAD-2006.12]CAD练习图例
- 变量的定义 声明和初始化和static
- 别把机器学习和人工智能搞混了!
- 华为安卓11是鸿蒙系统吗,恭喜华为手机,EMUI11曝光,是披着Android 11的“鸿蒙系统”?...
- 8、使用SELECTI...INTO OUTFILE导出表数据
- linux 进入一个中文乱码的目录的方法
- windows多用户 文件夹不共享_手把手教你如何使用Tekla多用户
- MySQL反斜杠 ‘\\‘ 插入数据库丢失
- 服务器安装、卸载宝塔面板
- 药品质量检测方法:电感耦合等离子体质谱仪
- android 指纹比对方法,指纹识别功能方面对比_手机Android频道-中关村在线
- 记录:nodejs 裁切图片的方法
- 微信小程序参数传递获取当前页面的url和参数
- hdu6194 string string string
- 一个初学者→全栈工程师的学习之路(1)——关于全栈工程师的理解
- 烧写android到开发板,烧写开发板_RZMars的技术博客_51CTO博客
- android webview问题汇总
- 2.2总线的性能指标
- HP惠普工作站无法启动虚拟机和蓝屏出现Technical information Stop:0x0000007B的解决办法