使用模块提供了一个Process
类实现多进程:
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process
实例,用start()
方法启动;
join()
方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步;
使用Process不需要close()直接join()就行。
from multiprocessing import Pool, Process, Queue
import os, time, random
def long_time_task(name, q):
print('Run task %s (%s)...' % (name, os.getpid()))
q.put({"TaskName": name, "pid": 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())
q = Queue()
for i in range(5):
p = Process(target=long_time_task, args=(i, q))
p.start()
p.join()
print('Waiting for all subprocesses done...')
# p.close()
for i in range(q.qsize()):
print(q.get())
print('All subprocesses done.')
运行结果
Parent process 3424.
Run task 0 (6880)...
Task 0 runs 1.21 seconds.
Run task 1 (7344)...
Task 1 runs 1.84 seconds.
Run task 2 (5572)...
Task 2 runs 1.56 seconds.
Run task 3 (6316)...
Task 3 runs 0.67 seconds.
Run task 4 (6196)...
Task 4 runs 2.83 seconds.
Waiting for all subprocesses done...
{'TaskName': 0, 'pid': 6880}
{'TaskName': 1, 'pid': 7344}
{'TaskName': 2, 'pid': 5572}
{'TaskName': 3, 'pid': 6316}
{'TaskName': 4, 'pid': 6196}
All subprocesses done.
Process finished with exit code 0
Pool类
Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到Pool中时,如果池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。
Pool 中提供了如下几个方法:
apply()
apply_async()
map()
map_async()
close()
terminal()
join()
apply和apply_async的区别:
apply方法是阻塞的:
首先主进程开始运行,碰到子进程,操作系统切换到子进程,等待子进程运行结束后,在切换到另外一个子进程,直到所有子进程运行完毕。然后在切换到主进程,运行剩余的部分。
apply_async 是异步非阻塞的:
首先主进程开始运行,碰到子进程后,主进程说:让我先运行个够,等到操作系统进行进程切换的时候,在交给子进程运行。以为我们的程序太短,然而还没等到操作系统进行进程切换,主进程就运行完毕了。
想要子进程执行,就告诉主进程:你等着所有子进程执行完毕后,在运行剩余部分。(p.close(), p.join())
p.close()关闭进程池,不再往进程池中添加新的进程。
python官方建议:废弃apply,使用apply_async。
使用POOL进程池的时候,Queue对象队列不能直接作为参数传递:
队列对象不能在父进程与子进程间通信,这个如果想要使用进程池中使用队列则要使用multiprocess的Manager类
manager = multiprocessing.Manager()
q = manager.Queue()
这样这个队列对象就可以在父进程与子进程间通信,不用池则不需要Manager。
关于锁的应用:
在不同程序间如果有同时对同一个队列操作的时候,为了避免错误,可以在某个函数操作队列的时候给它加把锁,这样在同一个时间内则只能有一个子进程对队列进行操作,锁也要在manager对象中的锁。
#coding:gbk
from multiprocessing import Process,Queue,Pool
import multiprocessing
import os, time, random
# 写数据进程执行的代码:
def write(q,lock):
lock.acquire() #加上锁
for value in ['A', 'B', 'C']:
print 'Put %s to queue...' % value
q.put(value)
lock.release() #释放锁
# 读数据进程执行的代码:
def read(q):
while True:
if not q.empty():
value = q.get(False)
print 'Get %s from queue.' % value
time.sleep(random.random())
else:
break
if __name__=='__main__':
manager = multiprocessing.Manager()
# 父进程创建Queue,并传给各个子进程:
q = manager.Queue()
lock = manager.Lock() #初始化一把锁
p = Pool()
pw = p.apply_async(write,args=(q,lock))
pr = p.apply_async(read,args=(q,))
p.close()
p.join()
print
print '所有数据都写入并且读完'
参考文章:
http://python.jobbole.com/86181/