Python之进程(multiprocessing)
一、multiprocessing模块简介——进程基于“threading”的接口
multiprocessing模块支持创建进程——使用threading模块相似的API。multiprocessing模块对本地和远程的并发都提供了支持,使用子进程(subprocesses)来替代threads解决了GIL的限制。因此,multiprocessing模块允许程序充分利用给定设备的多核资源。在Unix和Windows系统都可以运行。
multiprocessing模块同样引入了threading模块不支持的APIs。主要例子如:Pool对象提供了便捷并行执行(有多输入)的函数的执行,通过进程分发输入数据。下面就是一个简单的数据分发。
from multiprocessing import Pool def f(x): return x*x if __name__ == '__main__': p = Pool(5) print(p.map(f, [1, 2, 3]))
二、Process类
在multiprocessing模块中,processes可以通过创建一个Process对象产生。然后调用其start()方法。Process和threading.Thread遵循threading.Thread的API。一个简单的多线程例子如下
from multiprocessing import Process def f(name): print 'hello', name if __name__ == '__main__': p = Process(target=f, args=('bob',)) p.start() p.join()
显示相应的单个进程IDs,如下:
from multiprocessing import Process import os import time def info(title): print(title) print('module name:', __name__) if hasattr(os, 'getppid'): print('parent process:',os.getppid()) print('process id:', os.getpid()) def f(name): time.sleep(2) info('function f') print('hello', name) if __name__ == '__main__': info('main line') p = Process(target=f,args=('bob',)) p.start() p.join()
三、Exchanging objects between processes进程间通讯
1、Queue基本上是Queue.Queue的克隆版,但是本Queue是线程和进程都安全的
from multiprocessing import Process, Queue import time def f(q): time.sleep(2) q.put([42, None, 'hello']) print('f') if __name__ == '__main__': q = Queue() p = Process(target=f, args=(q,)) p.start() p.join() print('hello') print(q.get())
2、Pipes是Pipe()函数返回一个连接对象对——由一个pipe连接,默认是双工(两种方式)
from multiprocessing import Process, Pipe def f(conn): conn.send([42, None, 'hello']) conn.close() if __name__ == '__main__': parent_conn, child_conn = Pipe() p = Process(target=f, args=(child_conn,)) p.start() print(parent_conn.recv()) p.join()
Pipe()返回两个连接(Connection)对象,代表管道的两端。每个连接对象都有send()和recv()方法(彼此之间)。
注意:如果两个线程(或进程)同时尝试从pipe的同一端读写数据,管道里的数据可能损坏。如果同时在pipe()的两端读写是没有风险的。
四、进程间的同步机制
multiprocessing拥有threading模块相同的同步机制。例如,可以使用lock来保证一次只有一个进程打印到标准输出。
from multiprocessing import Process,Lock import time def f(l, i): l.acquire() # time.sleep(2) print('hello world', i) l.release() if __name__ == '__main__': lock = Lock() for num in range(10): Process(target=f,args=(lock, num)).start()
五、进程间共享状态
如上所述,我们在做并发编程时,应当尽可能避免使用共享状态。有其是多进程。然而,你非得在多进程使用共享数据,multiprocessing提供了几种方来实现。
1、Shared memory共享内存
数据可以存储在共享内存里使用Value或Array。例如,如下代码: