原文链接: http://www.juzicode.com/python-tutorial-multiprocess/
在 Python进阶教程m10–多线程 和 Python进阶教程m10b–多线程通信 我们介绍了多线程编程,并行编程模式中还有一种多进程编程模式,这篇文章将介绍到多进程编程。
1、编程模型
多进程需要用到multiprocessing模块,多进程编程模型可以参考多线程模型。 通过一个例子我们先来看下多进程的基本编程模型,在这个例子中主进程定义和开启了一个子进程,在子进程中打印自己的进程名称和循环次数,循环次数达到上限后退出子进程:
import os,time, multiprocessing
def func1():
proc_name = multiprocessing.current_process().name
proc_id = os.getpid()
print('进入进程: pid = ', proc_id,' name=',proc_name)
print('父进程id: ', os.getppid())
loopcnt = 0
while loopcnt < 10:
loopcnt = loopcnt + 1
print('进程: %s, loopcnt=%d' % (proc_id, loopcnt))
time.sleep(0.3)
print('退出进程: ' , proc_id)
if __name__ == '__main__':
print('\n-----欢迎来到www.juzicode.com')
print('-----公众号: 桔子code/juzicode \n')
proc_name = multiprocessing.current_process().name
proc_id = os.getpid()
print('进入主进程: pid = ', proc_id,' name=',proc_name)
p1 = multiprocessing.Process(target=func1, name='func1')
p1.start()
#p1.join()
time.sleep(5)
print('退出主进程: ' ,proc_id)
========运行结果:
-----欢迎来到www.juzicode.com
-----公众号: 桔子code/juzicode
进入主进程: pid = 13692 name= MainProcess
进入进程: pid = 26540 name= func1
父进程id: 13692
进程: 26540, loopcnt=1
进程: 26540, loopcnt=2
进程: 26540, loopcnt=3
进程: 26540, loopcnt=4
进程: 26540, loopcnt=5
进程: 26540, loopcnt=6
进程: 26540, loopcnt=7
进程: 26540, loopcnt=8
进程: 26540, loopcnt=9
进程: 26540, loopcnt=10
退出进程: 26540
退出主进程: 13692
从上面的例子可以看出多进程编程的基本模型和多线程是一样的:首先定义一个或多个任务函数,这个例子中定义了一个func1任务(函数);在主线程中用multiprocessing.Process()定义了这个任务的实例p1;然后使用 p1.start()启动func1任务。 注意在 Process (target=func1, name=’func1′)定义任务实例时,target入参是函数名称func1,而不是执行函数“func1()”的写法,是不带“()”符号的。
2、multiprocessing、进程对象的属性方法
2.1、 multiprocessing 属性、方法
通过multiprocessing 的属性和方法可以获取线程列表、活动线程数、线程ID等:
multiprocessing .active_children() | 获取活动子进程对象 | 返回包含子进程对象的list |
multiprocessing .current_process() | 返回当前进程对象 | 该对象下的name属性可以获取到当前进程的名称 |
多进程没有类似多线程get_ident()获取线程id的方法,但是可以使用os.getpid()获取该进程的编号,使用os.getppid()获取父进程的编号。
2.2、进程对象的属性、方法
通过multiprocessing.Process()创建的线程对象常用的属性、方法有:
is_alive() | 判断进程程对象是否是活动的 | 在使用start()启动线程前和线程结束后,调用该方法返回False |
name | 进程对象名称 | 仅仅用来标识,可以不是唯一的 |
start() | 开启进程 | 进程创建后只是创建了对象,需要使用start()方法开启进程。 |
join() | 等待进程结束 | 调用者会被阻塞,直到被启动进程结束,如果被启动进程中使用无限循环时需要小心 |
multiprocessing、进程对象的属性方法的一个例子:
import os,time, multiprocessing
def func1():
proc_name = multiprocessing.current_process().name
proc_id = os.getpid()
print('进入进程: pid = ', proc_id,' name=',proc_name)
print('父进程id: ', os.getppid())
loopcnt = 0
while loopcnt < 5:
loopcnt = loopcnt + 1
print('进程: %s, loopcnt=%d' % (proc_id, loopcnt))
time.sleep(0.2)
print('退出进程: ' , proc_id)
if __name__ == '__main__':
print('\n-----欢迎来到www.juzicode.com')
print('-----公众号: 桔子code/juzicode \n')
proc_name = multiprocessing.current_process().name
proc_id = os.getpid()
print('进入主进程: pid = ', proc_id,' name=',proc_name)
print('主进程的父进程id: ', os.getppid())
p1 = multiprocessing.Process(target=func1, name='func1')
p2 = multiprocessing.Process(target=func1, name='func2')
p1.start()
p2.start()
print('子进程1的名称:',p1.name)
print('子进程2的名称:',p2.name)
print('当前活动子进程数:', multiprocessing.active_children())
print('子进程1是否存活:',p1.is_alive())
print('子进程2是否存活:',p2.is_alive())
time.sleep(5)
print('主进程延时5s后:')
print('子进程1是否存活:',p1.is_alive())
print('子进程2是否存活:',p2.is_alive())
print('退出主进程: ' ,proc_id)
==========运行结果:
-----欢迎来到www.juzicode.com
-----公众号: 桔子code/juzicode
进入主进程: pid = 3868 name= MainProcess
主进程的父进程id: 10264
子进程1的名称: func1
子进程2的名称: func2
当前活动子进程数: [<Process name='func2' pid=21616 parent=3868 started>, <Process name='func1' pid=9796 parent=3868 started>]
子进程1是否存活: True
子进程2是否存活: True
进入进程: pid = 21616 name= func2
父进程id: 3868
进程: 21616, loopcnt=1
进入进程: pid = 9796 name= func1
父进程id: 3868
进程: 9796, loopcnt=1
进程: 21616, loopcnt=2
进程: 9796, loopcnt=2
进程: 21616, loopcnt=3
进程: 9796, loopcnt=3
进程: 21616, loopcnt=4
进程: 9796, loopcnt=4
进程: 21616, loopcnt=5
进程: 9796, loopcnt=5
退出进程: 21616
退出进程: 9796
主进程延时5s后:
子进程1是否存活: False
子进程2是否存活: False
退出主进程: 3868
3、创建进程的其他参数
args、kwargs、daemon等入参的功能和用法参照 Python进阶教程m10–多线程 。
4、多进程通信
多进程通信也可以使用 Manager、Pipe、Event、Lock 等并行编程工具包,使用方法参照 Python进阶教程m10b–多线程通信 。
推荐阅读: Python进阶教程m10–多线程 Python进阶教程m10b–多线程通信