文章目录
一、 多任务编程
多任务含义
就是操作系统可以同时运⾏多个任务。
现实中的多任务比如:手机上边听音乐边聊天,电脑上多个软件同时运行
单核CPU实现多任务
操作系统轮流让各个任务交替执⾏,每个任务执⾏0.01秒,这样反复执⾏下去。 表⾯上看,每个任务交替执⾏,但CPU的执⾏速度实在是太快了,感觉就像所有任务都在同时执⾏⼀样
逻辑上表现为:各个任务并发执行,即一个任务执行几秒后执行另一个任务,来回交替(同时运行,但是每个时间段只有一个任务执行)
物理上表现为:各个任务串行执行(第一个任务执行完之后再执行第二个任务)
多核CPU实现“多任务”
真正的并⾏执⾏多任务只能在多核CPU上实现,但是,由于任务数量远远多 于CPU的核⼼数量,所以,操作系统也会⾃动把很多任务轮流调度到每个核 ⼼上执⾏。
二、多进程编程
几个概念:
多进程编程:一个任务交给多个cpu
程序:编写完毕的代码,在没有运⾏的时候,称之为程序
进程:正在运⾏着的代码(程序),就成为进程
注意: 进程,除了包含代码以外,还有需要运⾏的环境等,所以和程序是有区别的
进程状态: 创建(created)-----就绪(ready)-----运行(running)-----阻塞(waiting)-----结束(terminated)
- 进程运行中cpu执行其他任务,造成进程中断,进入就绪状态,等待cpu分配时间片段
- 进行运行中需要等待一个输入,进入阻塞状态,接受输入,进入就绪阶段,等待cpu分配时间片段来running。在阻塞状态下让子进程去进行干其他事情,不浪费时间片段就是多进程编程。
创建进程
为什么需要多进程:当进入阻塞状态等待接受其他信息才能运行时,此时间片段浪费,可以进行其他任务使得时间合理化
多进程的条件:创建子进程
- Python的os模块中的fork()函数,用来创建子进程但是只能用在linux系统中
fork()函数理解:
执⾏到os.fork()时,操作系统会创建⼀个新的进程复制⽗进程的所有信息到⼦进程中
普通的函数调⽤,调⽤⼀次,返回⼀次,但是fork()调⽤⼀次,返回两次
⽗进程和⼦进程都会从fork()函数中得到⼀个返回值,⼦进程返回是0,⽽⽗进程中返回⼦进程的 id号,由于父进程会有许多子进程,为了记录父进程新加入的子进程需要在父进程中返回一个子进程的ID
思考问题:
fork拷贝父进程来创建子进程,修改全局变量,两个进程之间会有影响吗? fork到底对父进程拷贝了什么?
答:多进程修改全局变量,多进程中,每个进程中所有数据(包括全局变量)都各有拥有⼀份,父、子进程在内存的不同区域存储互不影响。
# 将当前进程使用fork拷贝一份子进程,同时在当前进程中定义一个全局变量money,在子进程中修改全局变量money,对比当前进程(父进程)与子进程的全局变量的值是否发生变化。
import os
import time
# 定义一个全局变量money
money = 100
print('当前进程pid:',os.getpid())
#为了更清楚的看到进程,让程序休眠
print('当前进程父id:',os.getppid()) #父进程为程序运行的大环境:pycharm
time.sleep(5)
p0bj=os.fork() #执行fork函数时:操作系统会将当前进程所有信息拷贝到⼦进程中
#fork()调⽤⼀次,返回两次
#⽗进程和⼦进程都会从fork()函数中得到⼀个返回值,⼦进程返回是0,⽽⽗进程中返回⼦进程的id号,用于记录父进程新创建的子进程
#⼦进程返回是0
if p0bj==0:
money = 200
print("子进程返回的信息, money=%d" % (money))
#⽗进程中返回⼦进程的pid
else:
print('创建子进程%s,父进程为%d'%(p0bj,os.getppid()))
print(money)
#执行结果:
创建子进程2508,父进程为11528
100
子进程返回的信息, money=200
- Windows没有fork调⽤,由于Python是跨平台的, multiprocessing模块就是跨平台版本 的多进程模块。
- multiprocessing模块提供了⼀个Process类来创建进程对象。
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调⽤对象;就是进程要执行的任务
args:表示调⽤对象的位置参数元组;
kwargs:表示调⽤对象的关键字参数字典;
name:为当前进程实例的别名;
group:⼤多数情况下⽤不到; - Process类常⽤⽅法:
is_alive() : 判断进程实例是否还在执⾏;
join([timeout]) : 等待当前进程执⾏完后主进程再继续执行;
start() : 启动进程实例(创建⼦进程);
run() : 如果没有给定target参数,对这个对象调⽤start()⽅法时,就将执 ⾏对象中的run()⽅法;
terminate() : 不管任务是否完成,⽴即终⽌; - Process类常⽤属性:
name:当前进程实例别名,默认Process-N,N为从1开始计数;
pid:当前进程实例的PID值
windows下多进程编程方法1: 实例化对象用于产生一个子进程。
Process:类
target参数:表示这个进程实例所调⽤对象;子进程要执行的任务
import time
from multiprocessing import Process
def task1(): #定义两个任务
print("正在听音乐")
time.sleep(1)
def task2():
print("正在编程......")
time.sleep(0.5)
def use_multi(): #使用多进程,需要在任务外部执行join
processes=[] #将所有任务创建好,再执行join等待
for i in range(2): #来一个任务开一个进程,多个任务用多个进程同时执行
p1 = Process(target=task1) #产生一个子进程,执行任务1
p1.start() #子进程执行任务
processes.append(p1)
for i in range(5):
p2 = Process(target=task2)
p2.start()
processes.append(p2)
#所有子进程任务创建好开始后,等待每一个进程的任务结束。
#开始第一个子进程的同时其他进程也在执行,直到一个一个的子进程全部结束
[process.join() for process in processes] 主进程阻塞,执行子进程,结束后再执行主进程。
if __name__ == '__main__':
# 主进程
start_time= time.time()
use_multi()
end_time = time.time()
print(end_time-start_time)
#3个进程同时执行:主进程、p1、p2, 并行
# 为了等两个子进程执行完后再执行主进