ちょっとした用事でウィーンへ行ってきて、昨日帰ってきたところです。時差ボケしてしんどいのですが、とりあえず忘れる前にメモしておきたいこと。

Pythonを「パイソン」と発音しても通じませんでした。
thの発音が重要だったのかも。
2007.07.28 Sat l Python l COM(0) TB(0) l top ▲
最も美しいソースコードは?
What's the most beautiful peice of code publicly available you sawより。

ここに挙がっているもので、読みたいものを上からリストアップ。
SQLite
Crypt++
Plan9
2007.07.15 Sun l ちょっと前に読んだもの l COM(0) TB(0) l top ▲
DjangoでLivedoorAuthを使う方法。こんな感じかなぁ。

お好み焼きともんじゃ焼きの食べ比べをして「どっちも結局はビールのつまみなんだから、野菜炒めで十分」という結論を出して、終電で帰ってきた。
LivedoorAuthを使うために、なんとなくviewを定義してみた。


from django.http import HttpResponseRedirect, HttpResponse

import time, sha, urllib, hmac

def jump(request):
query = { 'app_key': "...application_key...",
'perms': 'userhash',
't': str( int(time.time())),
'v': '1.0',
'userdata': request.POST.get('url','http://www.sample.net/')
}
sec_key = "...secret_key..."

sig = hmac.new(sec_key, digestmod=sha)
keys = query.keys()
keys.sort()
for key in keys:
sig.update(key)
sig.update(query[key])
query['sig'] = sig.hexdigest()
return HttpResponseRedirect('http://auth.livedoor.com/login/?%s'%urllib.urlencode(query))

def callback(request):
query = request.GET
sec_key = "...secret_key..."
sig = hmac.new(sec_key, digestmod=sha)
keys = query.keys()
keys.sort()
for key in keys:
if key == "sig":
continue
sig.update(key)
sig.update(query[key])
if sig.hexdigest() == request.GET.get("sig",""):
return HttpResponseRedirect(urllib.unquote(query.get("userdata","http://www.sample.net")))
else:
return HttpResponse("NG")


Sessionの管理とか、認証のURLのタイムアウトとか、いろいろやらなくちゃいけないことは残ってるけれど、とりあえず今夜はもう寝たい。
もっと簡単なやり方がありそうだけどなぁ…。
2007.07.15 Sun l Python Django l COM(0) TB(0) l top ▲
今、私は某企業でアルバイトをしています。仕事はソフトウェアのテストです。
このアルバイトをしていて思うのは、そのテストを究めていくキャリアパスっていうのが、あるのか、ないのか、ということです。
ソフトウェア以外の製造業ではどうなってるんだろうなぁ。

そういうことを、
Google New York Test Engineering Forum July 25を読んで、ふと思い出した。
2007.07.14 Sat l 未分類 l COM(0) TB(0) l top ▲
さくらインターネットで、DjangoをCGIとして動かす方法が、ようやくわかった。まる1日かかってようやく解決した。
参考にさせてもらったサイトをまとめ。私も、上の3つのリンク先ブログの中の人と同じ所ではまっていました…。
http://php-sql-gdgd.jugem.jp/?eid=22
http://php-sql-gdgd.jugem.jp/?eid=23
http://php-sql-gdgd.jugem.jp/?eid=24
http://www.panopticon.jp/blog/2007/04/011732.html
http://sh1.2-d.jp/b/2006-09-10-01-39.html
http://blog.joyfullife.jp/archives/2007/04/16134657.php
http://code.djangoproject.com/ticket/2407

それにしても、今さらだけど、週末が終わっちゃったなぁ。
2007.07.10 Tue l Python Django l COM(2) TB(0) l top ▲
いやなニュースはそもそも見ないという選択肢 LIFEHACKING.JPより。

テレビ(特にニュース)なんか見たって、結局、

どこかで子供が痛めつけられたとか、殺人事件があったとか、そういったニュースはそれ自体は非常に痛ましくて、なんとかしてあげたい気持ちにさせられますが、たいがいはもうすでに視聴者としての私にできることはなく、ただ後味の悪さが残るばかりです。


ということなんだ。だから見たってしょうがない。
じゃぁ、「見たってしょうがなくないニュース」っていうのは、どういうニュースなのか。…という発想をすると、人によって違うから、たぶん答えは出ない。なのに、テレビニュースは「多くの人にとって重要なニュース」を考えてしまうから、誰にでもほ〜んのちょっとだけ重要なニュースになってしまっている。
大切なのはニュースを見る目的をはっきりさせることだ。これは「どんなニュースだったら聞く意味があるのか」を考える前にやるべきことだ。そうすれば、見るべきニュースがはっきりしてくる。たとえば「安全な生活をしたい」という欲求があったとして、そのためにニュースを見るというのなら、見るべきニュースは「どっかの死体遺棄事件」よりも、警視庁の「犯罪発生マップ」の方だろう。だが、こういう情報を手に入れようと思ったら、テレビを見ていても無理だ。
そう考えていくと、どういう欲求があったときにテレビニュースを見ていたのか、よくわからなくなる。みんなが知ってる出来事を知って、話題についていけるようにするため?
2007.07.10 Tue l ちょっと前に読んだもの l COM(0) TB(0) l top ▲
Djangoをさくらインターネットのサーバで、CGIとして動かそうと試みているのだけれど、今日は失敗。
エラーのログが見れないのが辛いな〜。とりあえず自前のサーバに移してやってみるか。

とりあえず、参考にしているサイトのリスト
http://php-sql-gdgd.jugem.jp/?eid=23
http://www.panopticon.jp/blog/2007/04/011732.html
http://sh1.2-d.jp/b/2006-09-10-01-39.html
http://blog.joyfullife.jp/archives/2007/04/16134657.php

python manage.py runserver
でやるとちゃんと動くんだけどなぁ…。
2007.07.09 Mon l Python Django l COM(0) TB(1) l top ▲
PythonでWeb Applicationを作るためのフレームワークの1つであるDjangoの開発環境を、15分で作ることができます。
Virtual Appliance Blogsより。

ただし、VMware とかに詳しかったら、の話だけどね。
ってことで、LAMP VAを使えば、VMwareとかの仮想化ソフトに詳しければ、
15分以内で簡単にDjangoの開発環境を作ることができます。

仮想化に詳しくなるのに何分かかるんだ?って気もするけれど、でもWebプログラミングの敷居はどんどん下がってるんですね。
サーバを仮想化してシステムのTOCを下げる、みたいなのが最近流行ってるらしいし、
とりあえずこれも試してみようかなぁ…なんていろいろ手を出しすぎると、結局、中途半端になっちゃうんだよなぁ。
2007.07.09 Mon l Python Django l COM(0) TB(0) l top ▲
Left Hand Brewingのデザインがカッコよすぎる。

画面下部のメニューのOur Beersをクリックすると、この会社が取り扱っているビールの一覧(らしいもの)が表示されるんだけど、その銘柄をクリックすると、ビンのラベルが貼り替えられるところが最高にカッコいい。
というわけで、今夜は5時から友人とビールを飲みに行きます。
2007.07.07 Sat l ちょっと前に読んだもの l COM(0) TB(0) l top ▲
23 Programing Languages compared through thier Amazon book sales より

筆者は、エンジニアは金を(口ではなく)どの言語に使っているかを調べるために、それぞれの言語をアマゾンでの本の売り上げで比較している。
上位は

1. JavaScript
2. Java
3. Ruby
4. SQL
5. C#
6. C++
7. C
8. Visual Basic
9. Python
10. PHP
11. Perl
12. Erlang
13. Objective-C
14. Groovy
15. F#
16. Lua
17. Scheme
18. Hashkell
19. Delphi
20. Lisp
21. Forth
22. Smalltalk
23. Ocaml

というふうになっている。
リンクはWikipediaへのリンクになってるので、知らない言語があったらこの機会に調べて、
後で知ったかしましょう(笑)

それから筆者もコメントしてるけど、このリストはフレームワークとかを含んでないから、もろもろ入れると順位が変わりそう。
Railsとか、相変わらず人気だもんなぁ。

ところで、「アマゾンの売り上げで比較しました〜」っていう記事に商品へのリンクがあったら、「どんな本だろう?」って思ってついクリックしちゃうなぁ。
まぁ、英語だったから買わなかったけど。
2007.07.07 Sat l ちょっと前に読んだもの l COM(0) TB(0) l top ▲
+ NWS Iterator

NWS はデータをキューとして格納するんだけれども、イテレータとして使うこともできる。
ifind と+ NWS Iterator

NWS はデータをキューとして格納するんだけれども、イテレータとして使うこともできる。
ifind という関数がそれだ。対応づけられている値を順に返す。たとえば次のようなコードを考えてみる。

for v in range(5): ws.store('v', v)
for v in ws.ifind('v'): print v

このコードは、2つめのループで値を5つ表示したところで止まる。ifind関数が次の値を待つからだ。だから、別のプロセスで値がstoreされると、このプロセスは再び動き出す。
このプロセスを止めるには、

ws.deleteVar('v')

を実行する。
他にもこれを実現する方法はある。たとえば ifindTry という関数は、値を一通り返し終わったら終了する。ほかにも ifetch や ifetchTry という関数があって、これはキューを破壊しながらデータにアクセスする以外は、それぞれ ifind や ifindTry と同じだ。
NWS をイテレータとして使うには、FIFOかSingleモードの変数でなければならない。


+ Managing WorkSpaces
NWS は複数のワークスペースを管理することができて、コンストラクタに最初の引数として、ワークスペースの名前を渡すことになっている。ホストサーバを特定するために、ホスト名とポート番号を渡すこともできる。(っていうか、こういう仕組みは絶対必要だよね)たとえばこんなふうに。

ws = NetWorkSpace('example', serverHost='myhost.mycorp.com')

こうすれば、複数のプロセスで同じmyhost.mycorp.com の標準ポートで管理されるワークスペースを使うことができる。

でも、ワークスペースは誰のものでしょう。それは、普通、最初にワークスペースのことをサーバに言及したプロセスのものです。これはクリーンアップするときに重要になります。
ワークスペースとその中のデータは、永続的で、しっかりと消去されるまで残ります。実際、これはややこしいので、デフォルトではデータは一時的なものです。ワークスペースの持ち主のプロセスが終了したら、ワークスペースもなくなります。
でも、永続性は便利なと気もあるので、コンストラクタで設定すれば永続性を持たせることもできます。

ようするに、普通は、最初にワークスペースを使ったプロセスがワークスペースの持ち主。
他のプロセスはワークスペースを勝手に起動して、勝手に使って、勝手に逝ってよし。
そんで、持ち主のプロセスが死んだら、ワークスペースもなくなる。

でもまぁ、ワークスペースのオーナーにならないで使いたいってこともある。そんなときは、コンストラクタで useUse=True とすればよい。こんなふうに。

ws = NetWorkSpace('not mine', useUse=True)

ところで、このワークスペースの名前がぶつかっちゃったらどうするの?って心配するかもしれないけれど、大丈夫。
NWS には mkdtempWs っていうメソッドがあって、これはLinux の mkdtemp がユニークな名前のディレクトリを作るみたいに、サーバーの中でぶつからないワークスペースの名前を返してくれるんだ。


+ The Web Interface

NWS には、なんとウェブのインターフェースもある。
そのサーバーにあるワークスペースの一覧と、それぞれのワークスペースに含まれる変数の値を確認できる。また、これらを削除したり変更したりもできる。

それぞれの変数の値は、シリアライズされていて一見しただけではよく分からないけれど、Babelfish を使うと、それらをデシリアライズ(シリアライズの逆変換)して表示してくれる。Babelfishっていうのは、データを変換して返すだけの、ただのクライアントだ。

これを使うと、全体のシステムの初期値をブラウザから与えて実行するってこともできたりするよ。スレイ(Sleigh:馬車の意味)を使えば、の話だけどね。


+Sleigh

Sleigh を使えば、たくさんのプロセスの管理を簡単にやることができる。
これを使えば、master/worker スタイルの管理を、直接NWS を触らなくてできるようになる。

Sleigh はデフォルトで、ワーカーをローカルマシンに3つ作る。作られたワーカーは作業を渡されるのを待っている状態になっている。それは、こんなふうに書く。

>>> from nws.sleigh import Sleigh
>>> s = Sleigh()

eachWorkerというメソッドは、引数で与えられた関数をそれぞれのワーカーに対して実行して、その結果をリストにして返す。こんなふうに。

>>> from socket import gethostname
>>> s.eachWorker(gethostname)
['newt', 'newt', 'newt']

gethostname という関数は、ワーカーが動いているホスト名を返す。つまり作られたワーカーは、'newt'という名前のマシンで動いていることを表している。

ワーカーを1台のマシンでいくつも動かすのは、デバッグの時には有効だけれど、普通は複数のマシンで1つずつ動かしたいと思うだろう。
そんなときはこうする。

>>> s.stop()
>>> from nws.sleigh import sshcmd
>>> s = Sleigh(nodeList=['hippo', 'newt', 'python', 'rhino'], launch=sshcmd)
>>> s.eachWorker(gethostname)
['rhino', 'hippo', 'newt', 'python']

まず、最初の行で、今まで動いていたワーカーを止める。
そして3行めで、新しいワーカーを4台のホストで1つずつ動かして、それぞれsshで連携させている。
これは一応、ユーザがパスワード無しでログインできるように、うまく設定されたsshサーバを持ってることが前提だ。

eachWorkerは主に初期化に使って、実際に計算するときには、eachElemを使う。
これは関数とリストを引数に要求する関数だ。与えられた引数の各要素を、与えられた関数で評価して、その戻り値をリストにまとめて返してくれる。
たとえば前に紹介した、値の3乗のリストを求める計算は、こんなふうに書く。

>>> r = s.eachElem(lambda x: x*x*x, range(100))
>>> len(r)
100
>>> r[2:5]
[8, 27, 64]

eachElemに渡すリストは、当然、リストのリストとかでもOKだ。

デフォルトでは、eachElemメソッドは結果のリストが完成するまで値を返さない。
しかし、オプションを設定すれば、eachElem関数が結果のリストではなく、SleighPendingオブジェクトを返させることもできる。そうすればeachElemはブロックしない。SleighPendingオブジェクトは計算結果を問い合わせて、最終結果を得るためのメソッドを持っている。


+ Put It All Together

今まで紹介したことをまとめて、素数を見つけるプログラムを作る。
素数を見つけるアルゴリズムは、その数の平方根以下の全ての素数で割ってみて、全てで割り切れなかったら素数に追加する、という方式だ。
それを書くと、こんな風になる。

import sys
from nws.sleigh import Sleigh

def initPrimes():
global chunk, chunks, limit
limit, chunk = SleighUserNws.find('prime parameters')
chunks = {}
def findPrimes(first):
last = min(first+chunk, limit)
# we need to know all the primes up to the smaller of the start of
# this chunk or the square root of its last element.
need = min(first-2, int(.5+(last-1)**.5))

myPrimes = []
for c in xrange(3, need+1, chunk):
if not c in chunks: chunks[c] = SleighUserNws.find('primes%d'%c)
myPrimes += chunks[c]
newx = len(myPrimes)
for x in xrange(first, last, 2):
for p in myPrimes:
if x%p == 0: break
else: myPrimes.append(x)
if first**2 < limit: SleighUserNws.store('primes%d'%first, myPrimes[newx:])

return myPrimes[newx:]

def master(workers, limit, chunk):
s = Sleigh(workerCount=workers)
s.userNws.store('prime parameters', (limit, chunk))
s.eachWorker(initPrimes)
primes = [2]
map(primes.extend, s.eachElem(findPrimes, range(3, limit, chunk)))

return primes

if __name__=='__main__':
primes = master(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))
print len(primes), primes[:3], '...', primes[-3:]


まず、マスターがSleighのインスタンスを作って、eachWorkerを使ってワーカーを初期化する。それからタスクのリストを作ってeachElemで計算を始める。2つのパラメータがNWSに固定されて、eachWorker経由で参照される。それぞれのタスクは、素数かどうか調べる領域の最初の数で表現されている。素数かどうか調べるときに必要な素数のリストに、ワーカーが知らないものがあったら、ワーカーはfind関数を呼び出して調べる。ただ、ワーカーはそれぞれ自分が一度調べたものは記憶しておいて、find関数は呼び出さない。
ワーカーはSleighUserNwsというNWSを使っているが、これは名前がぶつからないようにSleighが作ったネームスペースだ。


+ Conclusion
これのすごいところは、並列プログラムをツールとかハードウエアなしに実現してしまうところ。マルチコアのCPUやたくさんのコンピュータがある環境でやるとよい。
また、計算と中にネームスペースのデータをWeb経由で参照できるので、デバッグがやりやすい。
しかも言語に依存しないので、いろんなプログラム言語で動かすことができる。


kawasaqの追記。
適当翻訳なので、わたし自身よくわかってないところもあります。
自分用のメモとして書きました。
もっとわかりやすい説明があったら教えてください。
ちなみに、NWSはここからダウンロードできます↓
http://www.lindaspaces.com/products/NWS_overview.html
2007.07.07 Sat l Python l COM(0) TB(0) l top ▲
こちらの記事は,後編とあわせてここにまとめました.(追記)

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 ▲
Vista shipped. So where are the new games?(Vistaは発売された。それで、新しいゲームはどこ?)より。

この記事によると、Vista用のゲームが出ていないのは、「Vistaが(まだ?)普及していないから」らしい。年末商戦に間に合わせられなかったのが、発売から6ヶ月経っても響いているそうだ。

言われてみれば、周りにVista使ってる人はいないな〜。発売されてからこの6ヶ月で4000万パッケージ以上が売れたらしいけど、世界で4000万ってどうなのよ。世界のPCの出荷台数は、たしか毎年2億何千万とかだから、半年で4000万って少なくない?

VistaやDirectX10の能力を使いきったゲームを見たら、感動して、「今のゲームでも十分速いから、新しいのはいらない」なんて話はどっかいっちゃうよ。
っていうコメントも、Wiiの人気とかを見ると、はたしてそんなにスピードを追い求めることが重要なのかと疑問に思えるけど…。
2007.07.02 Mon l ちょっと前に読んだもの l COM(0) TB(0) l top ▲