1. multiprocessing
模块提供了一个Process
类来代表一个进程对象:
(1) multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
以 tuple 的形式传入
将daemon设置为True时,则主线程不必等待子进程,主线程结束则所有结束
join() 方法实现进程间的同步,
等待所有进程退出。下面的例子演示了启动一个子进程并等待其结束
from multiprocessing import Process
import os
def run_proc(name):
print('Run child process %s (%s)...' % (name, os.getpid()))
if __name__ == '__main__':
print('Parent process %s.' % os.getpid())
p = Process(target = run_proc, args = ('test', ))
p.start()
p.join()
print('End')
输入结果如下:
Parent process 26524.
Run child process test (13336)...
End
其中os.getpid()是获取当前进程的进程号!
2. 如果要启动大量的子进程,可以用进程池的方式批量创建子进程
from multiprocessing import Pool
import os, time, random
def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Pool(4) # 创建4个进程
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('Waiting for all subprocesses done...')
p.close()
p.join()
print('All subprocesses done.')
Parent process 24496.
Waiting for all subprocesses done...
Run task 0 (3540)...
Run task 1 (25984)...
Run task 2 (14092)...
Run task 3 (20700)...
Task 3 runs 0.99 seconds.
Run task 4 (20700)...
Task 2 runs 1.35 seconds.
Task 0 runs 1.44 seconds.
Task 1 runs 2.48 seconds.
Task 4 runs 2.63 seconds.
All subprocesses done.
将p.apply_async()换成p.apply()后的输出为:
Run task 0 (12596)...
Task 0 runs 1.37 seconds.
Run task 1 (24548)...
Task 1 runs 0.59 seconds.
Run task 2 (21196)...
Task 2 runs 0.41 seconds.
Run task 3 (22572)...
Task 3 runs 0.42 seconds.
Run task 4 (12596)...
Task 4 runs 1.70 seconds.
Waiting for all subprocesses done...
All subprocesses done.
对Pool
对象调用join()
方法会等待所有子进程执行完毕,调用join()
之前必须先调用close()
,调用close()
之后就不能继续添加新的Process
了。
请注意输出的结果,task 0
,1
,2
,3
是立刻执行的,而task 4
要等待前面某个task完成后才执行,这是因为Pool
的默认大小在我的电脑上是4,因此,最多同时执行4个进程。这是Pool
有意设计的限制,并不是操作系统的限制。
其中:
(1) p.apply(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。需要强调的是:此操作 并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行func函数,必须从不同线程调用p.apply()函 数或者使用p.apply_async()
(2) p.apply_async(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。此方法的结果是 AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可用时,将理解传递给callback。 callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。多进程并发!
(3) p.close():关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
(4)P.jion():等待所有工作进程退出。此方法只能在close()或teminate()之后调用
3. 进程间通信
Process
之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing
模块包装了底层的机制,提供了Queue
、Pipes
等多种方式来交换数据。
我们以Queue
为例,在父进程中创建两个子进程,一个往Queue
里写数据,一个从Queue
里读数据:
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
print('Process to write: %s' % os.getpid())
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
print('Process to read: %s' % os.getpid())
while True:
value = q.get(True)
print('Get %s from queue.' % value)
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
pr.terminate()
Process to write: 17372
Put A to queue...
Process to read: 23988
Get A from queue.
Put B to queue...
Get B from queue.
Put C to queue...
Get C from queue.