Personal tools

2.6に新搭載のmultiprocessingを見て俺のPythonがおっきした件

by ats posted at 2008-09-05 00:36 last modified 2008-09-05 02:08

いやー,multiprocessingモジュールイイよ。パねえよ。要はプロセス間通信を行うときに便利なパッケージで,threadingと似たようなAPIなのでGILが回避できてマルチプロセッサとかマルチコアの性能を有効に使えてウハウハとか,リモートマシンにあるプロセスと通信したりオブジェクトをやりとりしたりできてウハウハとか,まあそういうモノです。これでおっきしない奴は技術者として大切な資質を失っていると思うよ。べつにおっきしなくてもいいんだけど,そういう奴とは一緒に仕事したくないよ。

ドキュメントのイントロダクションを超訳してみたです。


はじめに

multiprocessingはthreadingモジュールと似たAPIを使ってプロセスを生成するパッケージです。 multiprocessingパッケージはローカルとリモートマシンのプロセス並行制御をサポートしています。スレッドの代わりにプロセスを使うことで,GIL(Global Interpreter Lock)が起こす問題を効果的に避けることができます。multiprocessingモジュールを使うことによって,プログラマはマルチプロセッサの恩恵を十二分に享受できるようになります。このモジュールはUnixとWindowsで動作します。

Processクラス

multiprocessingでは,プロセスはProcessオブジェクトを作り,start()メソッドを呼ぶことによって生成します。Processクラスは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()


このコードにあるf()という関数は,子プロセスで稼働します。

Windowsで「if __name__ == '__main__'」という部分が必要な理由については,「プログラミングガイドライン」を見て下さい。


プロセス間通信をするために,multiprocessingでは,2つの方法をサポートしています。


Queue(キュー)

QueueクラスはQueue.Queueとよく似ています。たとえば,次のような使い方をします。


    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()


Queueオブジェクトはスレッド/プロセスセーフです。

Pipes

Pipe()関数はパイプで接続した2つの接続オブジェクトを返します。デフォルトでは双方向通信を行うオブジェクトを返します。以下のような使い方をします。


    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()


Pipe()関数が返す2つのコネクションオブジェクトはパイプの2つの端のようなものです。それぞれのコネクションオブジェクトは反対の端と通信を行うためのsend()とrecv()メソッドを持っています。2つのプロセス(またはスレッド)が同時に,パイプの同じ側で受信,または送信をしようとすると,パイプの中のデータが壊れてしまうことがあることに注意して下さい。もちろん,パイプの両端で送受信をすれば,データが壊れるリスクはありません。


複数プロセス間の同期

multiprocessingはthreadingが持つ同期をするための仕組みを持っています。ひとつのプロセスだけが標準出力に出力することを保証するためにlockを使ったりできます。以下がサンプルです。

from multiprocessing import Process, Lock

def f(l, i):
    l.acquire()
    print 'hello world', i
    l.release()

if __name__ == '__main__':
    lock = Lock()

    for num in range(10):
        Process(target=f, args=(lock, num)).start()

他のプロセスからの出力をロックしてやらないと,出力が入り交じってしまうことがあります。

状態をプロセス間で共有する

直前に言及したように,たいていの場合,並行プログラミングを行うための最良の方法は,可能な限り状態の共有を避けることです。このことは複数プロセスを使ったプログラミングをするときには特にそうです。
とはいえ,どうしても情報を複数プロセス間で共有する必要がある場合のために,multiprocessingは手法を2つ提供しています。

共有メモリ

ValueやArrayを使うことによって,データを共有メモリ上に保存できます。以下がサンプルコードです。

    from multiprocessing import Process, Value, Array

    def f(n, a):
        n.value = 3.1415927
        for i in range(len(a)):
            a[i] = -a[i]

    if __name__ == '__main__':
        num = Value('d', 0.0)
        arr = Array('i', range(10))

        p = Process(target=f, args=(num, arr))
        p.start()
        p.join()

        print num.value
        print arr[:]

このコードは,以下のような出力をします。

    3.1415927
    [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

'd'と'i'という引数はarrayモジュールで使われる型コードです。numとarrオブジェクトの型を指定するために使います。'd'はfloat型,'i'は符号付き整数を示します。共有オブジェクトはスレッド/プロセスセーフになります。
より柔軟に共有メモリーを活用できるように,任意のctypesオブジェクトの生成をサポートするmultiprocessing.sharedctypesを使うこともできます。

サーバプロセス

Manager()が返すmanagerオブジェクトを使うと,Pythonオブジェクトを保持するサーバプロセスをコントロールできます。また,プロキシーを使って他のプロセスを操作できます。
Manager()が返すmanagerオブジェクトはリスト型,辞書型,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,ValueやArrayを扱えます。以下がサンプルコードです。

    from multiprocessing import Process, Manager

    def f(d, l):
        d[1] = '1'
        d['2'] = 2
        d[0.25] = None
        l.reverse()

    if __name__ == '__main__':
        manager = Manager()

        d = manager.dict()
        l = manager.list(range(10))

        p = Process(target=f, args=(d, l))
        p.start()
        p.join()

        print d
        print l

このコードは以下のような出力をします。

    {0.25: None, 1: '1', '2': 2}
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

複数サーバプロセスのmanagerオブジェクトは,共有メモリより柔軟です。なぜなら、managerオブジェクトでは任意のデータ型を利用できるからです。さらに,単体のmanagerオブジェクトは,異なるコンピュータ上にある複数のプロセス上でネットワークを通じて共有できます。ただし,managerオブジェクトは共有メモリよりも遅いのが難点です。

ワーカプールを使う

Poolクラスはワーカプロセスのプールの役割を果たします。Poolクラスのメソッドを使うと,タスクをワーカプロセスとして振る舞わせることができます。方法はいくつかあります。以下がサンプルコードです。

from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    pool = Pool(processes=4)              # start 4 worker processes
    result = pool.applyAsync(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]"







The URL to Trackback this entry is:
http://coreblog.org/ats/multiprocessing-package/tbping

Re:2.6に新搭載のmultiprocessingを見て俺のPythonがおっきした件

Posted by Anonymous User at 2008-09-17 17:41
こ、これはやばいw

俺様Actorや、俺様Cache鯖が素直に実装できてしまうではないですかwww

線路関係の仕事しか振ってこない環境が嘆かわしい・・

Re:2.6に新搭載のmultiprocessingを見て俺のPythonがおっきした件

Posted by hohehohe2 at 2008-10-15 20:06
いいですよね。
最初見たときGIL回避のためだけかと思ってましたがプロセス間通信もやっちゃえーってノリでしょうか(GIL回避だけでも十分うれしいんですが)

Shared memory

Data can be stored in a shared memory map using Value or Array.

も感じいいです。
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
(Required)
コメントスパム避けのための認証文字列です

Captcha Image

Pythonな求人
r = urlopen("http://www.webcore.co.jp/recruit")
About this blog
■Author


atsこと柴田淳です。この記事を読んでいただくと,技術者としての人となりを分かってもらえるかも。
Webcore株式会社 代表取締役
Plone上で動く,オープンソースのBlog Product - COREBlog2を使って運用しています。

最近書いた原稿
Python 3.0 Hacks 第6回 Pythonicな文字列フォーマットforamat()メソッド 2009-03-30
言語としての一貫性を重視したPython 3の進化 2009-02-20
Python 3が後方互換性を捨てても求めたもの 2009-02-02
Python 3.0 Hacks : 第0回 Pythonの2008-2009 2009-01-01
柴田 淳のコーディング天国 - 貧弱環境プログラミングのススメ 2008-09-03
 
最近書いた本,Mook
みんなのPython 改訂版
Python使いはもちろん,プログラミングの初心者から,他言語からの移行組までご好評いただいているPythonの定番入門書の第2版です。Python 3.0を含む最新の情報について加筆を行い,より読みやすいように構成を大幅に見直しました。第一版をお持ちの方にもお役立ていただける内容になっています。
みんなのPython Webアプリ編
Pythonの基礎から,Webアプリやフレームワークの仕組みまで,つまることなく一気に学べる書籍です。「みんなのPython」と一緒に読んでください:-)。
 

Powered by Plone, the Open Source Content Management System