多进程
一、多任务原理
-
概念
现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支持“多任务”的操作系统
-
什么叫多任务?
就是操作系统可以同时运行多个任务
-
单核CPU实现多任务原理
操作系统轮流让各个任务交替执行,QQ执行2us(微秒),切换到微信,在执行2us,再切换到陌陌,执行2us……。表面是看,每个任务反复执行下去,但是CPU调度执行速度太快了,导致我们感觉就像所有任务都在同时执行一样
-
多核CPU实现多任务原理
真正的秉性执行多任务只能在多核CPU上实现,但是由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行
-
并发与并行
-
并发
CPU调度执行速度太快了,看上去一起执行,任务数多于CPU核心数
-
并行
真正一起执行,任务数小于等于CPU核心数
-
并发是逻辑上的同时发生,并行更多是侧重于物理上的同时发生。
-
-
实现多任务的方式
-
多进程模式
启动多个进程,每个进程虽然只有一个线程,但是多个进程可以一起执行多个任务
-
多线程模式
启动一个进程,在一个进程的内部启动多个线程,这样多个线程也可以一起执行多个任务
-
多进程+多线程
启动多个进程,每个进程再启动多个线程
-
协程
-
多进程+协程
-
二、进程
1、概念
-
什么是进程?
是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
-
对于操作系统
一个任务就是一个进程。比方说打开浏览器就是启动一个浏览器的进程,在打开一个记事本就启动一个记事本进程,如果打开两个记事本就启动两个记事本进程
2、使用进程
单进程现象
需要等待代码执行完后再执行下一段代码
import time
def run1():
while 1:
print("lucky is a good man")
time.sleep(1)
def run2():
while 1:
print("lucky is a nice man")
time.sleep(1)
if __name__ == "__main__":
run1()
# 不会执行run2()函数,只有上面的run1()结束才能执行run2()
run2()
-
启动进程实现多任务
-
multiprocessing模块
跨平台的多进程模块,提供了一个Process类用来实例化一个进程对象
-
Process类
作用:创建进程(子进程)
-
__name__
-
这是 Windows 上多进程的实现问题。在 Windows 上,子进程会自动 import 启动它的这个文件,而在 import 的时候是会执行这些语句的。如果你这么写的话就会无限递归创建子进程报错。所以必须把创建子进程的部分用那个 if 判断保护起来,import 的时候
__name__
不是__main__
,就不会递归运行了。参数 说明 target 指定进程执行的任务 args 给进程函数传递的参数,是一个元组 注意:此时进程被创建,但是不会启动进程执行
-
启动进程实现多任务
from multiprocessing import Process
创建子进程
P = Process(target=run,args=(“nice”,),name=‘当前进程名称’)
-
target指定 子进程运行的函数
-
args 指定传递的参数 , 是元组类型
-
启动进程:Process对象.start()
获取进程信息
- os.getpid() 获取当前进程id号
- os.getppid() 获取当前进程的父进程id号
- multiprocessing.current_process().name 获取当前进程名称
父子进程的先后顺序
-
默认 父进程的结束不能影响子进程 让父进程等待子进程结束再执行父进程
-
p.join() 阻塞当前进程,直到调用join方法的那个进程执行完,再继续执行当前进程。
-
全局变量在过个进程中不能共享
注意: 在子进程中修改全局变量时对父进程中的全局变量没有影响
-
- 示例代码
-
import time
from multiprocessing import Process
def run1(name):
while 1:
print("%s is a good man"%name)
time.sleep(1)
def run2():
while 1:
print("lucky is a nice man")
time.sleep(1)
if __name__ == "__main__":
# 程序启动时的进程称为主进程(父进程)
# 创建进程并启动
p = Process(target=run1, args=("lucky",))
p.start()
# 主进程执行run2()函数
run2()
- 主进程负责调度
主进程主要做的是调度相关的工作,一般不负责具体业务逻辑
import time
from multiprocessing import Process
def run1():
for i in range(7):
print("lucky is a good man")
time.sleep(1)
def run2(name, word):
for i in range(5):
print("%s is a %s man"%(name, word))
time.sleep(1)
if __name__ == "__main__":
t1 = time.time()
# 创建两个进程分别执行run1、run2
p1 = Process(target=run1)
p2 = Process(target=run2, args=("lucky", "cool"))
# 启动两个进程
p1.start()
p2.start()
# 查看耗时
t2 = time.time()
print("耗时:%.2f"%(t2-t1))
- 父子进程的先后顺序
主进程的结束不能影响子进程,所以可以等待子进程的结束再结束主进程,等待子进程结束,才能继续运行主进程
p.join() 阻塞当前进程,直到调用join方法的那个进程执行完,再继续执行当前进程。
import time
from multiprocessing import Process
def run1():
for i in range(7):
print("lucky is a good man")
time.sleep(1)
def run2