多进程模块 multiprocessing 是用来管理多进程的,因为 multiprocessing 模块能充分利用多核 CPU 的优势(因为线程有全局解释器锁的存在),它可以避免一些计算瓶颈(computational bottlenecks)。
基础
最简单的生成一个进程的方式是实例化一个 Process 对象,传递一个参数 target函数,然后调用 start() 方法。
执行:
例子中,实例化了3个进程,打印了3次 worker。
向进程传递参数
通常,要告诉生成的进程一些信息,可以通过 args 参数传递值。和 threading 不同的是,args 参数要可以被 pickle 序列化。
执行:
导入 target 函数
上面的例子中,和 threading 模块中的代码不同的是,使用 __name__ == '__main__' 进行了判断。这么做的原因是当子进程开始时,需要导入 target 函数所在的模块,为了防止重复导入(递归)。另一种方式是把 target 函数放在一个单独的脚本里。
worker.py 文件包含了函数 worker()
获取当前进程名称
不需要把进程名称传入到 target() 函数,这样很别扭(cumbersome)而且没有必要(unnecessary)。每个 Process 对象都有一个 name 属性,这样可以很容易的跟踪到是哪个进程。
执行:
后台进程(Daemon Process)
默认,主程序直到所有的子进程退出后才退出。有时候需要让子进程去后台进行工作而不干扰主进程的退出。只需要传递参数 daemon 为 True,就可以把子进程放入后台。
执行:
查看输出,后台进程并没有打印 exiting 信息,主进程休眠了1秒就结束了。
当主进程退出时,子进程自动停止运行,这样避免孤儿进程继续运行。
等待后台进程
执行:
使用 join() 方法,主进程会等待子进程运行完毕,最后后台进程打印了 exiting信息。
join() 方法会一直阻塞至子进程完成工作,你也可以传递一个超时的秒数,如果进程在超时的时间内还没有完成工作,也会按时返回。
结束进程
例如进程挂起或者发生死锁的时候,可以使用 terminate() 方法结束进程。
执行:
`terminate()` 后需要紧跟 `join()` 方法,为了使进程管理器有时间更新进程的状态。
退出状态
进程的退出状态可以通过属性 exitcode 访问。退出状态三种情况:
0 没有发生错误
> 0 进程遇到错误
< 0 使用信号结束了进程,信号值是 -1 * exitcode
执行:
函数 f1 调用了 sys.exit(1) 指定了进程退出值 1。
函数 f2 和 f3 正常返回了,没有指定退出值,默认为0,代表未发生错误。
函数 f4 抛出了异常,该进程返回了错误值1
函数 f5 调用了 terminate() 结束了进程,使用的是信号,返回负值 -15。
自定义类
虽然使用 Process 和 target 函数可以很容易的生成一个进程。但有时你可能可以使用自定义类生成进程。
执行:
| 留言与评论(共有 0 条评论) |