Process 类:
fork() 方法只在类 linux 系统下可以使用,在 windows 下无法使用;
但是 python 是跨平台的,自然也应该提供一个跨平台的多进程支持;
multiprocessing 模块就是跨平台版本的多进程模块,即在 linux 系统下和 windows 系统下都可以使用;
multiprocessing 模块提供了一个 Process 类来代表一个进程;
以下例子用 Process 类创建一个子进程:
# 导入 multiprocessing 模块中的 Process 类
from multiprocessing import Process
import time
# 定义一个函数:子进程要执行的代码
def test():
# 在子进程中每隔 1 秒循环输出一次
for i in range(5):
print("--- test --- ", i)
time.sleep(1) # 停顿 1 秒
if __name__ == "__main__":
# 实例化一个 Process 对象,即创建一个子进程对象;
# 并通过 target 参数指定子进程执行的目标对象(test函数);
p = Process(target=test)
# start() 方法用于启动子进程对象,即开始执行 test 函数里的代码;
p.start()
# 主进程中也是每隔 1 秒循环输出一次(可以发现主进程和子进程是同时执行的)
for i in range(2):
print("--- main --- ", i)
time.sleep(1)
输出结果:
注意:从输出结果可以看出,使用 Process 对象创建的子进程,如果在执行耗时操作,那么主进程不会结束,而是一直等待子进程,直到所有子进程全部结束,主进程才会结束。
但是使用 fork() 方法创建的子进程,如果在执行耗时操作,主进程是可以先行结束的,不用管子进程有没有结束;如下代码所示:
import os
import time
# 使用 fork() 方法创建子进程
ret = os.fork()
if ret == 0: # 子进程
for i in range(5):
print("--- test --- ", i)
time.sleep(1)
elif ret > 0: # 父进程
for i in range(2):
print("--- main --- ", i)
time.sleep(1)
输出结果:
总结:推荐使用 Process 类创建子进程,不建议使用 fork 方法;因为最好让主进程在子进程之后结束,这样在子进程结束的时候,主进程可以为子进程回收资源,释放内存等;如果一个子进程先结束了,而主进程没有为子进程回收资源,那么这个子进程叫做僵尸进城;如果一个主进程先结束了,而子进程还没有结束,那么这个子进程叫做孤儿进程;
Process 语法结构:
Process([group [, target [, name [, args [, kwargs]]]]]):
group:大多数情况下用不到;
target:表示这个进程实例所调用的对象(即子进程中执行的函数);
name:表示当前进程实例的别名;
args:表示调用对象的位置参数元组(即传入函数的参数,用元组表示);
kwargs:表示调用对象的关键字参数字典;
Process 类常用方法:
is_alive():判断进程实例是否还在执行;
join([timeout]):是否等待进程实例执行结束,或等待多少秒;
start():启动进程实例(创建子进程);
run():如果没有给定 target 参数,在调用进程对象的 start() 方法时,就执行进程对象中的 run() 方法;
terminate():不管任务是否完成,立刻终止;
Process 类常用属性:
name:当前进程实例别名;默认为 Process-N,N 为从 1 开始递增的整数;
pid:当前进程实例的 pid 值;
# 导入 multiprocessing 模块中的 Process 类
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name, age):
print("子进程:pid=%d, name=%s, age=%d" %(os.getpid(), name, age))
if __name__ == "__main__":
print("父进程:", os.getpid())
# 实例化一个子进程对象
# 指定一个执行函数的引用,和传入函数的参数
p = Process(target=run_proc, args=("test", 22))
print("子进程将要执行")
# start() 方法用于启动子进程
p.start()
# join() 方法用于等待子进程执行结束后,再继续往下执行,通常用于进程间的同步;
# 如果没有 join() 方法,将会先输出 “子进程结束”,然后在执行子进程里的方法;
p.join()
print("子进程结束")
print("name:", p.name) # 当前进程实例别名,默认为 Process-N,N 为从 1 开始递增的整数
print("pid:", p.pid) # 当前进程实例的 pid 值
输出结果:
Process 类创建子进程的第二种方法:
自定义一个类,继承于 Process 类,并在自定义类中重写 Process 类的 run() 方法,run() 方法就是子进程中执行的代码;
调用自定义类的 start() 方法时,会自动执行 run() 方法;
每次实例化自定义类的时候,就等于创建一个子进程对象;
# 导入 multiprocessing 模块中的 Process 类
from multiprocessing import Process
import os
import time
# 自定义一个类,继承于 Process 类
class MyProcess(Process):
# Process 类本身也有一个 __init__ 方法,子类相当于重写了这个方法;
# 但这样就会带来一个问题,我们并没有完全的初始化一个 Process 类,
# 所以就不能使用从这个类继承的一些方法和属性;
# 最好的办法就是将子类传递给 Process 的 __init__ 方法,完成初始化操作。
def __init__(self, interval):
Process.__init__(self)
self.interval = interval
# 重写 Process 类的 run 方法
def run(self):
print("子进程(%d)开始执行,父进程为 %d" %(os.getpid(), os.getppid()))
# time.time():表示从 1970年1月1号0时0分0秒 到现在的秒数
t_start = time.time() # 记录开始时间
time.sleep(self.interval)
t_stop = time.time() # 记录结束时间
print("%d 执行结束,耗时 %0.2f 秒" %(os.getpid(), t_stop - t_start))
if __name__ == "__main__":
print("主进程 ", os.getpid())
t_start = time.time()
# 实例化对象,就是创建一个子进程对象
# 参数 2 是传递到子进程中的延迟间隔
p = MyProcess(2)
# 调用子进程对象的 start() 方法,就会自动执行类中的 run() 方法
p.start()
# join() 方法用于阻塞子进程,即等待子进程执行结束后,在继续向下执行
p.join()
t_stop = time.time()
print("%d 执行结束,耗时 %0.2f 秒" %(os.getpid(), t_stop - t_start))