GAE上ではジェネレータを保存出来なかった話 

はてなブックマーク - GAE上ではジェネレータを保存出来なかった話
Bookmark this on Delicious

先日ジェネレータを一旦保存しておいて、途中から再実行するというエントリを書きました。これで何がしたかったかと言うと、この方法を使うとリクエストあたりの30秒制限があるGAEでも、割と綺麗に擬似的な無限ループが表現出来るだろうと言う事で実験していました。もっと言えばGAEでクローラを作りたかった訳ですが、残念ながら出来ませんでしたという話です。

まず僕が書きたかったのは以下の様なコードです。かなり単純ですがクローラの様な雰囲気ですね。本来はrunが無限ループ的に実行されていて、dispatcherとhandlerを繰り返し呼ぶ感じだと思いますが、ここでは簡単のためdispatcherをジェネレータにして、handlerは省略しています。これでrunを繰り返しcron等で呼び出す事で、擬似的に無限ループを表現できますね。保存用に変数等を用意していないのが好ましいと思います。

from generator_tools import loads, dumps
 
def get_dispatcher():
  links = get_some_links()
  while len(links) > 0:
    yield links.pop()
 
def run():
  cache = memcache.get('dispatcher')
  dispatcher = cache and loads(cache) or get_dispatcher(fetch)
  try:
    while True:
  	  link = dispatcher.next()
	  crawl_link(link)
  except DeadlineExceededError:
    memcache.add('dispatcher', dumps(dispatcher)) or memcache.replace('dispatcher', dumps(dispatcher))
  return HttpResponse('success to run')

しかしこのコードは残念ながらGAEの本番環境上では動きません。上記コードを実行すると、generator_tools.loadsの呼出しで、RuntimeError: cannot create code objects in restricted execution modeというエラーがでます。どういう事か調べてみると、generator_toolsはジェネレータを保存する時に、自身のopコードを文字列に変換します。その文字列で表されたopコードを元に実行コードを復元する訳ですが、その復元処理がセキュリティ上の問題から禁止されているようです。まぁ考えてみると当たり前の制限なんですが残念です。ちなみに開発環境では問題なく動作するので注意が必要です。開発環境で書き上げたコードがボツになったので,僕はショックで1日現実逃避しました。

なお上記のget_dispatcherしたジェネレータをgenerator_tools.dumpsすると以下の様な文字列になります。Pythonのopコード(の文字列表現)初めて見ましたが、割と単純でJavaVMのより読み易い印象ですね。

ccopy_reg
_reconstructor
p0
(cgenerator_tools.picklegenerators
SnapshotEnvelope
p1
c__builtin__
object
p2
Ntp3
Rp4
(dp5
S'obj'
p6
g0
 
# 長いので以下省略

前回のエントリで面白い事が出来るかもと言ったのは、この疑似無限ループのことで、他の使い方は思いつかないので、別に面白い事は出来ませんでした。ちゃんちゃん。

関連する記事

タグ: , ,

コメントをどうぞ