通过multiprocessing的Process类,我们可以创建一个Process对象。Process类类似于Python线程中的threading.Thread,可以通过这里了解一下。
直接上代码:
# encoding=utf8
import os
from multiprocessing import Process
s = '\033[31;42m'
e = '\033[0m'
def grandson(parent):
print "--- %ssubprocess %s's son: %s is running%s" % (s, parent, os.getpid(), e)
def run(num):
pid = os.getpid()
print '- Child %s process %s is running' % (num, pid)
p = Process(target=grandson, args=(pid, ))
p.start()
p.join()
if __name__ == '__main__':
print 'Parent process %s is running' % os.getpid()
for i in range(3):
p = Process(target=run, args=(i,))
p.start()
p.join()
print 'Parent is end'
运行结果:
上面的例子中,主进程创建了3个子进程,每个子进程又各自创建了一个子进程(孙子进程)。
1.说明
1.在向Process传入args参数的时候要使用元组,且传入的参数只有一个的时候要写成:(i,),否则会报错;
2.start方法:启动子进程;
3.join方法:子进程使用join可以让主进程进入等待(阻塞主进程),子进程全部结束后,主进程才继续执行。
2.设置守护进程
将子进程的daemon值设置为True,这时候子进程会随着主进程结束而结束,需要注意的是,设置守护进程应该在start()执行之前,否则会报错;同时,如果子进程设置了守护进程,子进程就不能再创建自己的子进程了。而且,如果想要使用守护进程,子进程就不要再调用join()函数了,否则p.daemon = True会失效(子进程依然会阻塞主进程)。
代码示例:
# encoding=utf8
import os
from multiprocessing import Process
s = '\033[31;42m'
e = '\033[0m'
def grandson(parent):
print "--- %ssubprocess %s's son: %s is running%s" % (s, parent, os.getpid(), e)
def run(num):
pid = os.getpid()
print '- Child %s process %s is running' % (num, pid)
p = Process(target=grandson, args=(pid, ))
p.start()
p.join()
if __name__ == '__main__':
print 'Parent process %s is running' % os.getpid()
for i in range(3):
p = Process(target=run, args=(i,))
p.daemon = True
p.start()
print 'Parent is end'
运行结果:
Parent process 51904 is running
Parent is end
通过结果可以知道,子进程设置守护进程后,主进程结束的时候,子进程也就结束了。
3.进程间资源不共享
进程与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内,不会影响父进程内的资源。示例:
# encoding=utf8
from multiprocessing import Process
from threading import Thread
n = 100
def work(name):
global n
n = 0
print '当前%s内的n值为: %s' % (name, n)
if __name__ == '__main__':
p = Process(target=work, args=('子进程',))
p.start()
p.join()
print '主进程n值为: ',n
print '-' * 33
t = Thread(target=work, args=('子线程',))
t.start()
t.join()
print '主进程n值为: ',n
运行结果:
当前子进程内的n值为: 0
主进程n值为: 100
---------------------------------
当前子线程内的n值为: 0
主进程n值为: 0
上面的例子可以表明,子进程与主进程之间没有共享资源,但是子线程是可以调用和影响父进程资源的。
最后,推荐一篇相关博文:。
----- 2018年4月24日 更新 -----
今天通过官方文档看到其他方法,可以实现主进程和子进程间的资源共享,一种是使用multiprocessing的共享对象(共享内存)Value和Array来实现,它们是可以保证进程安全和线程安全的:
# coding:utf-8
from multiprocessing import Process, Value, Array
def f(n, a):
n.value = 1.23456
for i in range(len(a)):
a[i] = -a[i]
def main():
num = Value('d', 0.0) # d表示双精度浮点型
arr = Array('i', range(10)) # i表示带符号的整型
p = Process(target=f, args=(num, arr))
p.start()
p.join()
print 'num: ', num.value
print 'arr: ', arr[:]
if __name__ == '__main__':
main()
运行结果:
num: 1.23456
arr: [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
另一种就是使用服务器进程Manager:
# coding:utf-8
from multiprocessing import Process, Manager
def f(d, l):
d[1] = '1'
d['2'] = 2
d[0.25] = None
l.reverse()
def main():
manager = Manager()
d = manager.dict()
l = manager.list(range(10))
p = Process(target=f, args=(d, l))
p.start()
p.join()
print '--- d: ', d
print '--- l: ', l
if __name__ == '__main__':
main()
运行结果:
--- d: {0.25: None, 1: '1', '2': 2}
--- l: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
manager对象支持的数据类型有:list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Queue, Value and Array。
Manager比Value和Array使用起来更灵活,因为它支持更多类型的对象。一个manager对象可以通过网络接口共享给不同机器上的进程。当然,Manager使用起来可能会比共享内存慢。