多任务编程
多任务概述
即操作系统中可以同时运行多个任务。比如我们可以同时挂着qq,听音乐,同时上网浏览网页。这是我们看得到的任务,在系统中还有很多系统任务在执行,现在的操作系统基本都是多任务操作系统,具备运行多任务的能力
cpu轮询机制,cpu都在多个任务之间快速的切换执行,切换速度在微秒级别,其实cpu同时只执行一个任务,但是因为切换太快了,从应用层看好像所有任务同时在执行
- 多核CPU:现在的计算机一般都是多核CPU,比如四核,八核,我们可以理解为由多个单核CPU的集合。这时候在执行任务时就有了选择,可以将多个任务分配给某一个cpu核心,也可以将多个任务分配给多个cpu核心,操作系统会自动根据任务的复杂程度选择最优的分配方案。
- 并发 : 多个任务如果被分配给了一个cpu内核,那么这多个任务之间就是并发关系,并发关系的多个任务之间并不是真正的"同时"。
- 并行 : 多个任务如果被分配给了不同的cpu内核,那么这多个任务之间执行时就是并行关系,并行关系的多个任务时真正的“同时”执行
什么是多任务编程
- 多任务编程即一个程序中编写多个任务,在程序运行时让这多个任务一起运行,而不是一个一个的顺次执行.比如微信视频聊天,这时候在微信运行过程中既用到了视频任务也用到了音频任务,甚至同时还能发消息。这就是典型的多任务。而实际的开发过程中这样的情况比比皆是
多任务意义
- 提高了任务之间的配合,可以根据运行情况进行任务创建。
- 充分利用计算机资源,提高了任务的执行效率。
- 在任务中无阻塞时只有并行状态才能提高效率
- 在任务中有阻塞时并行并发都能提高效率
进程(Process)
进程概述
- 程序在计算机中的一次执行过程
- 程序是一个可执行的文件,是静态的占有磁盘
- 进程是一个动态的过程描述,占有计算机运行资源,有一定的生命周期
进程状态
- 三态
- 就绪态:进程具备执行条件,等待系统调度分配cpu资源
- 运行态:进程占有cpu正在运行
- 等待态:进程阻塞等待,此时会让出cpu
五态 (在三态基础上增加新建和终止)
- 新建:创建一个进程,获取资源的过程
- 终止:进程结束,释放资源的过程
进程命令
#查看进程信息
ps -aux
#进程树形结构
#父子进程:在Linux操作系统中,进程形成树形关系,任务上一级进程是下一级的父进程,下一级进程是上一级的子进程
pstree
- USER : 进程的创建者
- PID : 操作系统分配给进程的编号,大于0的整数,系统中每个进程的PID都不重复。PID也是重要的区分进程的标志。
- %CPU,%MEM : 占有的CPU和内存
- STAT : 进程状态信息,S I 表示阻塞状态 ,R 表示就绪状态或者运行状态
- START : 进程启动时间
- COMMAND : 通过什么程序启动的进程
多进程编程
使用模块 multiprocessing
- 创建流程
- 将需要新进程执行的事件封装为函数
- 通过模块的Process类创建进程对象,关联函数
- 通过进程对象调用start启动进程
- 主要类和函数使用
Process()
功能 : 创建进程对象
参数 : target 绑定要执行的目标函数
args 元组,用于给target函数位置传参
kwargs 字典,给target函数键值传参
daemon bool值,让子进程随父进程退出
p.start()
功能 : 启动进程
#注意 : 启动进程此时target绑定函数开始执行,该函数作为新进程执行内容,此时进程真正被创建
p.join([timeout])
功能:阻塞等待子进程退出
参数:最长等待时间
进程创建示例:
"""
进程创建示例 01
"""
import multiprocessing as mp
from time import sleep
a = 1 # 全局变量
# 进程目标函数
def fun():
print("开始运行一个进程")
sleep(4) # 模拟事件执行事件
global a
print("a =",a) # Yes
a = 10000
print("进程执行结束")
# 实例化进程对象
process = mp.Process(target=fun)
# 启动进程 进程产生 执行fun
process.start()
print("我也做点事情")
sleep(3)
print("我也把事情做完了...")
process.join() # 阻塞等待子进程结束
print("a:",a) # 1 10000
"""
进程创建示例02 : 含有参数的进程函数
"""
from multiprocessing import Process
from time import sleep
# 含有参数的进程函数
def worker(sec,name):
for i in range(3):
sleep(sec)
print("I'm %s"%name)
print("I'm working....")
# 元组位置传参
# p = Process(target=worker,args=(2,"Tom"))
# 关键字传参
p = Process(target=worker,
args = (2,),
kwargs={"name":"Tom"},
daemon=True) # 子进程伴随父进程结束
p.start()
sleep(3)
进程执行现象理解
- 新的进程是原有进程的子进程,子进程复制父进程全部内存空间代码段,一个进程可以创建多个子进程。
- 子进程只执行指定的函数,其余内容均是父进程执行内容,但是子进程也拥有其他父进程资源。
- 各个进程在执行上互不影响,也没有先后顺序关系。
- 进程创建后,各个进程空间独立,相互没有影响。
multiprocessing
创建的子进程中无法使用标准输入(即无法使用input)
进程处理细节
进程相关函数
os.getpid()
功能: 获取一个进程的PID值
返回值: 返回当前进程的PID
os.getppid()
功能: 获取父进程的PID号
返回值: 返回父进程PID
sys.exit(info)
功能:退出进程
参数:字符串 表示退出时打印内容
"""
创建多个子进程
"""
from multiprocessing import Process
from time import sleep
import sys, os
def th1():
sleep(3)
print("吃饭")
print(os.getppid(), "--", os.getpid())
def th2():
# sys.exit("不能睡觉了") # 进程结束
sleep(1)
print("睡觉")
print(os.getppid(), "--", os.getpid())
def th3():
sleep(2)
print("打豆豆")
print(os.getppid(), "--", os.getpid())
# 循环创建子进程
jobs = [] # 存放每个进程对象
for th in [th1, th2, th3]:
p = Process(target=th)
jobs.append(p) # 存入jobs
p.start()
# 确保三件事都结束
for i in jobs:
i.join()
print("三件事完成")
孤儿进程和僵尸进程
- 孤儿进程: 父进程先于子进程退出时,子进程会成为孤儿进程,孤儿进程会被系统自动收养,成为孤儿进程新的父进程,并在孤儿进程退出时释放其资源。
- 僵尸进程: 子进程先于父进程退出,父进程又没有处理子进程的退出状态,此时子进程就会成为僵尸进程。
- 特点:僵尸进程虽然结束,但是会存留部分进程资源在内存中,大量的僵尸进程会浪费系统资源。Python模块当中自动建立了僵尸处理机制,每次创建新进程都进行检查,将之前产生的僵尸处理掉,而且父进程退出前,僵尸也会被自动处理。
创建进程类
进程的基本创建方法将子进程执行的内容封装为函数。如果我们更热衷于面向对象的编程思想,也可以使用类来封装进程内容
- 创建步骤
- 继承
Process
类 - 重写
__init__
方法添加自己的属性,使用super()
加载父类属性 - 重写
run()
方法
- 使用方法
- 实例化对象
- 调用start自动执行run方法
"""
自定义进程类
"""
from multiprocessing import Process
from time import sleep
class MyProcess(Process):
def __init__(self, value):
self.value = value
super().__init__() # 调用父类的init
# 重写run 作为进程的执行内容
def run(self):
for i in range(self.value):
sleep(2)
print("自定义进程类。。。。")
p = MyProcess(3)
p.start() # 将 run方法作为进程执行
进程间通信
进程间空间独立,资源不共享,此时在需要进程间数据传输时就需要特定的手段进行数据通信。常用进程间通信方法:消息队列,套接字等
- 消息队列通信原理:在内存中开辟空间,建立队列模型,进程通过队列将消息存入,或者从队列取出完成进程间通信。
from multiprocessing import Queue
q = Queue(maxsize=0)
功能: 创建队列对象
参数:最多存放消息个数
返回值:队列对象
q.put(data)
功能:向队列存入消息
参数:data 要存入的内容
q.get()
功能:从队列取出消息
返回值: 返回获取到的内容
q.full() 判断队列是否为满
q.empty() 判断队列是否为空
q.qsize() 获取队列中消息个数
q.close() 关闭队列
进程间通信示例:
from multiprocessing import Process,Queue
# 创建消息队列
q = Queue(5)
# 子进程函数
def handle():
while True:
cmd = q.get() # 取出指令
if cmd == "1":
print("\n完成指令1")
elif cmd == "2":
print("\n完成指令2")
# 创建进程
p = Process(target=handle,daemon=True)
p.start()
while True:
cmd = input("指令:")
if not cmd:
break
q.put(cmd) # 通过队列给子进程
最后一次更新于2022-11-25 14:47
0 条评论