为啥用multiprocessing?

*现在cpu都多核了, 写大型程序你还在用单线程的传统写法?很不fashion而且效率很低, 你out了。 

*那用multi-threading不就结了?C语言可以, 编译完执行没问题。 但是python这种解释型的语言用多线程就不行了, python的multithreading效率并不高。据说是受制于GIL (global interpreter lock) 的锁机制, 该锁只能工作于单个cpu core。这样别的cpu core干着急也帮不上忙。

*那怎么办呢? 自己fork一堆子进程,然后管理呗? 呵呵,DIY?这不是重新造轮子吗。

*亲, 用python现成的multiprocessing库吧。支持多个cpu core,简直就是为了多核cpu打造的, python 2.6之后都支持。

来点sample,

*sample 1, 创建process, target=f 函数名, args传递参数

from multiprocessing import Process


def f(name):

    print 'hello', name


if __name__ == '__main__':

    p = Process(target=f, args=('bob',))

    p.start()

    p.join()

*sample2.1,  支持队列

from multiprocessing import Process, Queue


def f(q):

    q.put([42, None, 'hello'])


if __name__ == '__main__':

    q = Queue()

    p = Process(target=f, args=(q,))

    p.start()

    print q.get()    # prints "[42, None, 'hello']"

    p.join()

Sample 2.2, 支持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()   # prints "[42, None, 'hello']"

    p.join()

Sample3,  支持Pool, 雇一群worker来干活

from multiprocessing import Pool


def f(x):

    return x*x


if __name__ == '__main__':

    pool = Pool(processes=4)              # start 4 worker processes


    result = pool.apply_async(f, (10,))    # evaluate "f(10)" asynchronously

    print result.get(timeout=1)           # prints "100" unless your computer is *very* slow


    print pool.map(f, range(10))          # prints "[0, 1, 4,..., 81]"


    it = pool.imap(f, range(10))

    print it.next()                       # prints "0"

    print it.next()                       # prints "1"

    print it.next(timeout=1)              # prints "4" unless your computer is *very* slow


    import time

    result = pool.apply_async(time.sleep, (10,))

    print result.get(timeout=1)           # raises TimeoutError

其他高级的特性, 比如Manager类,shared memory,请看官网文档,参考文献2

注意事项:

* 在UNIX平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie)。所以,有必要对每个Process对象调用join()方法 (实际上等同于wait)。对于多线程来说,由于只有一个进程,所以不存在此必要性。

* multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。

* 多进程应该避免共享资源。在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过共享内存和Manager的方法来共享资源。但这样做提高了程序的复杂度,并因为同步的需要而降低了程序的效率。

Reference:

[1] http://www.ibm.com/developerworks/aix/library/au-multiprocessing

[2] http://docs.python.org/2/library/multiprocessing.html

[3] http://blog.csdn.net/jj_liuxin/article/details/3564365

[4] http://www.cnblogs.com/vamei/archive/2012/10/12/2721484.html