こちらの記事は,後編とあわせてここにまとめました.(追記)

Python NetWorkSpaces(NWS)と並列プログラミング
http://www.ddj.com/dept/architect/200001971?pgno=1
より
Python と NetWorkSpaces を使うと、並列プログラムが簡単に作れる。

NetWorkSpaces というのは、並列プログラムを簡単に書くためのライブラリ。
いわゆる「ネームスペース」をシェアする形で、複数のプログラム間でデータをやりとりする。

たとえば、こんなふうに。


ws.store('x', ws.fetch('y'))
ws.x = ws.y


この2行は同じだ。 ws というのがネームスペースを表す識別子で、
そのネームスペース上の y に関連付けられているデータを x に関連付ける。

もうちょっと詳しく書くと、たとえば Python だったらこんな感じ。


>>> from nws.client import NetWorkSpace
>>> ws=NetWorkSpace('test')
>>> l=['a','b','c']
>>> t=(1,2,3)
>>> d={'list':l, 'tuple':t}
>>> ws.store('dict example', d)
>>> ws.fetch('dict example')
{'list': ['a', 'b', 'c'], 'tuple': (1, 2, 3)}


NetWorkSpaces というのは、別に Python だけのものってわけじゃなくて、
たとえば R でも使える。特にデータがASCII文字だったら、次の例のように、言語が違うプログラムでデータをやりとりできる。


Python
>>> from nws.client import NetWorkSpace
>>> ws=NetWorkSpace('tickets')
>>> ws.store('ticket', 'ticket string')

R
> library(nws)
> ws<-netWorkSpace('tickets')
> nwsFetch(ws, 'ticket')
[1] "ticket string"



ところで、最初の例で示したws.x, ws.y などは、代入で上書きされる普通の変数ではなく
FIFOのキューだ。ws.y というキューにデータが入っていないときは、ws.fetch("y")を実行すると、単に待たされる。
これを理解するためには、次のようなコードを試してみるとよい。
"worker"として


from nws.client import NetWorkSpace
def f(x): return x*x*x
ws = NetWorkSpace('table')
while True:
ws.store('r', f(ws.fetch('x')))


というプログラムを動かして、同時に"Master"として


ws = NetWorkSpace('table')
for x in range(100): ws.store('x', x)
for x in range(100): print 'f(%d) = %d'%(x, ws.fetch('r'))


というプログラムを動かす。
すると、1ずつ増えていく数とその数を3乗した数の対のリストが得られるだろう。
こんなふうに、workerとmasterは別々に動く。workerが複数いるときは、
workerのプログラムを若干書きなおさなくてはいけないけれど、masterの方は同じでよい。
ああ、なんてフレキシブル。

次に、y = f(x) の最大値を求めるために、複数のプログラムが x の候補となるリストを持っている場合を考える。
たとえば、こんなプログラムを書いて並列で実行するとどうなるだろう。


for x in MyCandidateList:
currentMax = ws.fetch('max')
y = f(x)
if y > currentMax: ws.store('max', y)


これはもちろん、誤ったプログラムだ。fetch したままで値を store しない場合がある。
こんなときのために、キューを変更しないで値だけ見るための関数 find が用意されている。
じゃぁ find を使ってこんなプログラムを書いたらどうだろう。


for x in MyCandidateList:
currentMax = ws.find('max')
y = f(x)
if y > currentMax: ws.store('max', y)


これも誤りだ。storeされるばっかりでキューが長くなって、find で参照される値が最新のものでなくなってしまう。
というわけで、こういうふうに書くのが正しい。


for x in MyCandidateList:
currentMax = ws.find('max')
y = f(x)
if y > currentMax:
currentMax = ws.fetch('max')
if y > currentMax: currentMax = y
ws.store('max', currentMax)


一見冗長に見えるかもしれないけれど、これが正しい。fetch と store が対になっているので、原子性も保証される。
currentMax は毎回 find を使わなくても、10回に1回 find したり、あるいは最初に適当な値を入れておいて、1つ目のif文が成立したときだけに
書き換えるようにしてもうまくいく。

ところで、このようにキューを破壊しないでデータを参照する find の使い道として、
最初に初期化として値を与えておいて、あとはそれを定数として参照するだけ、という使い方がある。

その他、NWS では次のようなモデルをサポートしている

- FIFO (default)
- LIFO
- 非決定的(ランダムではなくて、任意に)
- Single (ただ1つの値を保持して、store関数はその値を上書きする)

Singleというモデルは、たとえばステータスを渡すときに役に立つ。いちいち以前の値をfetchして消さなくていいしね。
サンプルコードはこんな感じ。


from nws.client import SINGLE
ws.declare('status', SINGLE)
while True:
time.sleep(60)
status=...
ws.store('status', status)



簡単に並列計算 Python and NetWorkSpaces 後半
2007.07.06 Fri l Python l COM(0) TB(1) l top ▲

コメント

コメントの投稿












       

トラックバック

トラックバックURL
→http://kawasaq.blog56.fc2.com/tb.php/35-8918f521
この記事にトラックバックする(FC2ブログユーザー)
http://kawasaq.blog56.fc2.com/blog-entry-35.html > NetWorkSpaces というのは、並列プログラムを簡単に書くためのライブラリ。 > いわゆる「ネームスペース」をシェアする形で、複数のプログラム間でデータをやりとりする。 http://www.ddj.com/dept/architect/
2007.07.22 Sun l name-3333の日記