Python学习笔记(二十五):使用跨平台的 Process 创建子进程

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))

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值