What for generator in python 2.
相変わらず、Generatorを口説き中。中々仲良くなってくれない感じ。
とりあえづ、生い立ちを調べてみた。http://www.python.jp/pipermail/python-ml-jp/2001-July/000466.html
動機
生産者(producer)関数が生産される値の間で状態の維持を要求するという難
しい仕事がある場合、ほとんどの言語は、生産される値ごとに呼び出される
コールバック関数を生産者関数の引数リストに付加する以上の、快適で効率
的な解決策を提供していない。
と言うことらしい。分かったようなわからんような・・・
また、以下のようなコメントも貰ったので
1) Treeをvisit/walkしてnodeをyieldするコードを書いてみる
2) 魅力的なPython: Pythonジェネレーターで「無重量スレッド」を実装する http://www.ibm.com/developerworks/jp/linux/library/l-pythrd/
3)
def f():
pass
だとジェネレータにならずに関数になってしまう。どうしたらよいか?
でかいデータを扱うときに、リストなどにデータを一気にためると
メモリ的に辛いときがあります。
generatorだと、その都度評価なのでメモリを使わないので良いです。
とりあえづ、コード書いてみることにした。分かってないけど、使ってみるうちに分かるよね。
最初は、yield使わないバージョン。巨大な配列を作成する。その前後でメモリーの状態を計り増加分をモニターする。
import os def memEater(cnt): # メモリー消費ちゃん # cnt ** cnt 数の配列を作る arr = [] for i in range(cnt): for ii in range(cnt): arr.append(ii) return arr def old_main(): loop_cnt = 1000 mem0 = os.popen('/bin/ps -o vsz %d' % (os.getpid())).readlines()[-1] memEater(loop_cnt) mem1 = os.popen('/bin/ps -o vsz %d' % (os.getpid())).readlines()[-1] print int(mem1) - int(mem0)
実行してみる
603148
6113408192
まぁ、別にたいしたことない。
yield使って見る。
def getMemGene(): mem0 = os.popen('/bin/ps -o vsz %d' % (os.getpid())).readlines()[-1] mem1 = 0 while 1: mem1 = os.popen('/bin/ps -o vsz %d' % (os.getpid())).readlines()[-1] yield int(mem1) - int(mem0) mem0 = mem1 def memEaterGene(cnt): arr, memusage = [], getMemGene() for i in range(cnt): for ii in range(cnt): yield (ii, memusage.next())
これは良いかも知れないと言う気が軽くしてきた。どこで使うか明確なポイントは思い浮かばないけど、必要な時に必要な計算だけしてくれる。さらに、その次にも思いついたタイミングでさっきの続きを気軽にリクエストできる。
メモリーの消費量を比較してみた。数字が100000000個入った配列を作成するだけだけど、1.3GB消費と、計測不能なくらいちょっとKB消費となった。
まぁ、作るだけだとこんな感じなる。iterだと作った後に、ランダムに2000番目と1000番目の足し算とか出来ないから毎度作る必要がある。リアル配列だったら一回作ればどこでもアクセス出来る。
デカイ配列を使う時にGeneratorが良いと言っても、メモリーに十分入るほどのデカイ配列であればlistで良い気がしなくもない。というか、それほどメリットを感じない。for がnext()してくれるらしいのでIterもListも変わらない。Listは一個前もどこでも保持されてるし、書き換えられる(!書き換えられないという事がメリットか!?)
まぁ、どっちを使うかはlist生成に関しては好みのような気がしてきた。(あくまでオンメモリ可能であれば)
引き続き、ヒントをやってみます。