1 简介
最近一段时间由于用到了Python的multiprocessing,在这里对multiprocessing的使用做一个总结。
由于CPython使用GIL (Global Interpreter Lock)来是的Python能够定位和访问要执行的代码的位置,那么造成了Python在multithread的情况下,仍然是串行执行的方式。
由于GIL是进程级别的,那么multiprocessing就是用多进程的方式来进行并行执行来提高系统CPU使用率的目的。
2 基本代码样式
multithread和multiprocessing的代码基本类似,可以使用函数作为worker的执行主体,也可以使用类继承的方式来执行worker的执行单元。
multi-thread version:
from threading import Thread
class MyThread(Thread):
def __init__(self):
Thread.__init__(self):
def run(self):
a, b = 0, 1
for i in range(0,100000):
a, b = b, a+b
if __main__ == "__main__":
t = MyThread()
t.start()
t.join()
multiprocessing version:
from multiprocessing import Process
class MyProcess(Process):
def __init__(self):
Thread.__init__(self):
def run(self):
a, b = 0, 1
for i in range(0,100000):
a, b = b, a+b
if __main__ == "__main__":
p = MyProcess()
p.start()
print p.pid
print p.join()
print p.exitcode
3 性能
由于GIL问题导致多线程的性能问题远低于多进程,甚至数倍于单线程版本:

4 apply和map函数
apply和map函数分别用于启动单一进程和启动一批次的worker进程的函数,例如
def foo(arg):
return isprime(arg)
for i in range(0,10):
result = apply(foo, i)
上述例子并不是一个真实的多进程使用的apply函数的例子,该函数启动foo进程用于计算该参数是否是个质数。并将结果返回,当apply函数返回后,进入下一i的循环,再次启动另外一个新的实例来执行。也就是说该进程用apply启动的方式是阻塞方式(相对于main进程来说)。
如果主进程不希望被阻塞,那么使用apply_async函数,该函数需要另外一个callback参数,该参数用于指定的一个接收该进程返回结果的处理函数。该回调函数将接收一个为AsyncResult类型的参数。进程foo的执行结果在AsyncResult.get()中。该函数被main进程调用,而不是worker process。被apply_async启动起来的进程是不能保证进程的启动顺序的,这一点要注意。apply(foo)相当于apply_async_foo).get()`
map函数用于启动一组函数,map函数接收一个可以迭代的集合并将该集合均分到启动的函数中,例如:
a = range(0,100)
def foo(args):
return [isprime(i) for i in args]
pool=MultiProcessing.Pool(foo,number=10)
results=pool.map(foo,a, 10)
上述大致的代码将启动10个foo进程,每一个将处理10个数字。返回的结果也将保存在一个数组中。
map函数也有对应的async版本 -- map_async,同样也不能保证进程的执行顺序。
如果使用async版本的启动函数,那么在主进程中需要使用pool.join来等待worker进程的结束。
4 RPC
可以使用Multiprocessing中的Pipe或者Queue来进行进程通信,Pipe也可以通过MultiProcessing.Manager将该对象绑定到端口上来实现cross node的通信。
1 简介
最近一段时间由于用到了Python的
multiprocessing,在这里对multiprocessing的使用做一个总结。由于CPython使用GIL (Global Interpreter Lock)来是的Python能够定位和访问要执行的代码的位置,那么造成了Python在multithread的情况下,仍然是串行执行的方式。
由于GIL是进程级别的,那么multiprocessing就是用多进程的方式来进行并行执行来提高系统CPU使用率的目的。
2 基本代码样式
multithread和multiprocessing的代码基本类似,可以使用函数作为worker的执行主体,也可以使用类继承的方式来执行worker的执行单元。
multi-thread version:
multiprocessing version:
3 性能
由于GIL问题导致多线程的性能问题远低于多进程,甚至数倍于单线程版本:

4 apply和map函数
apply和map函数分别用于启动单一进程和启动一批次的worker进程的函数,例如上述例子并不是一个真实的多进程使用的apply函数的例子,该函数启动foo进程用于计算该参数是否是个质数。并将结果返回,当apply函数返回后,进入下一i的循环,再次启动另外一个新的实例来执行。也就是说该进程用
apply启动的方式是阻塞方式(相对于main进程来说)。如果主进程不希望被阻塞,那么使用
apply_async函数,该函数需要另外一个callback参数,该参数用于指定的一个接收该进程返回结果的处理函数。该回调函数将接收一个为AsyncResult类型的参数。进程foo的执行结果在AsyncResult.get()中。该函数被main进程调用,而不是worker process。被apply_async启动起来的进程是不能保证进程的启动顺序的,这一点要注意。apply(foo)相当于apply_async_foo).get()`map函数用于启动一组函数,map函数接收一个可以迭代的集合并将该集合均分到启动的函数中,例如:上述大致的代码将启动10个foo进程,每一个将处理10个数字。返回的结果也将保存在一个数组中。
map函数也有对应的async版本 --map_async,同样也不能保证进程的执行顺序。如果使用async版本的启动函数,那么在主进程中需要使用pool.join来等待worker进程的结束。
4 RPC
可以使用Multiprocessing中的
Pipe或者Queue来进行进程通信,Pipe也可以通过MultiProcessing.Manager将该对象绑定到端口上来实现cross node的通信。