Home > Uncategorized Archive

Uncategorized Archive

新型インフルエンザ

木曜日ぐらいから発熱・悪寒がすごくて、病院に行ってきたら新型インフルエンザと診察されました。来週1週間は出禁とのことです。今はタミフルを飲んで少し熱が下がってきた感じです。

検査などは特にされなかったのですが、症状的に見て、ほとんど間違いないとのことです。検査の精度が約60%程度であることと、あと同じような症状の人が前に並んでいたので、安全側に倒す+手間を省いてるのだと思います。

病院に行ってみて分かったのですが、予想以上に流行ってるという印象です・・・。皆様もお気をつけてくださいませ・・・。

# 各方面の方々には、色々迷惑をかけてまして、本当にすいません。。。

曽爾村に帰省

十年ぶりぐらいに父親の実家(奈良県宇陀郡曽爾村)に帰省しました。自然しかない!サマーウォーズみた直後だったので、ちょっとテンションあがりました。草刈りのお手伝いとかしてきました。

太田家

縁側

彼岸花

とんぼ


すすき(曽爾高原)

全写真リスト

Twinado = Tornado + async-python-twitter

Twinadoという携帯向けのTwitterクライアントを書いてみました。日常的に使えるレベルにはなっていると思います。

特徴としては最近Facebookが公開したTornadoというフレームワークを使って、Twitter API呼び出しが全て非同期に行われている点です。なので、コネクション数が増えても高速に動くはずです。現状DoCoMo P905iでしか動作確認していません。

きっかけとしては、最近Perl界隈で非同期処理が流行っているのを見て、楽しそうだと思っていたところに、Tornadoが公開されたので、少し使ってみるかと思い立った事です。Tornadoについては以下を参考にして下さい(日本語訳、お疲れ様です!)。

Tornadoの特徴は、リクエストハンドラ内でHTTPリクエストを非同期に発行出来る事です。これによって、サーバー側でのネットワークの待ち時間を減らし、その間に別のリクエストを処理する事が出来ます。以下のサンプルコードは、FriendFeedのAPIを非同期で取得している例になります。取得終了時にon_response関数が呼ばれます。


class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        http = tornado.httpclient.AsyncHTTPClient()
        http.fetch("http://friendfeed-api.com/v2/feed/bret",
                   callback=self.async_callback(self.on_response))

    def on_response(self, response):
        if response.error: raise tornado.web.HTTPError(500)
        json = tornado.escape.json_decode(response.body)
        self.write("Fetched " + str(len(json["entries"])) + " entries "
                   "from the FriendFeed API")
        self.finish()

で、何か作ろうと思って、激しく外部APIアクセスするものって何かなと思ったところ、Twitterクライアントしか思いつかなかったので、作る事にしました。PythonのTwitterクライアントライブラリ「python-twitter」とTornadoに付属しているAsyncHTTPClientを密結合させました。

変更後のソースはgithubにおいてあります。今のところ、一部の関数のみ非同期呼び出しに対応しています。差分を見て頂くと分かりますが、_FetchUrlAsync関数が肝です。

APIの非同期呼び出しは以下のように書けます。GetUserコマンドに渡しているasync_callbackというのがポイントです。読み込みが終わった瞬間に引数で渡した関数を呼び出してくれます。on_response関数ではAPIで取得したUserクラスのインスタンスが渡って来ます。


class UserMainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self, username, password):
        try:
            api = async_twitter.Api(username, password)
            api.GetUser(user = username,
                        async_callback = self.async_callback(self.on_response))
        except:
            self.write("twitter api failed")
            print sys.exc_info()
            self.finish()

    def on_response(self, user):
        if user == None:
            self.write("twitter api failed")
            self.finish()
            return
        self.do_render(user)

    def do_render(self, user):
        self.render("tpl/user_main.html",
                    user = user)

この辺でかなり満足し切ったのですが、適当に機能を足して、冒頭で紹介したTwinadoという携帯向けのTwitterクライアントを書いてみました。

Tornadoで書いてみた雑感ですが、コールバックベースの非同期処理は記述が面倒臭すぎます。特にAPIを複数回呼びだしたりする必要の有る処理なんかは、コールバック関数をその都度作らないといけない。

また結果を引き回すために関数のcurry化をしたいのだけど、pythonだとfunctoolsというモジュールで明示的に関数を作ってやる必要が有ったり、楽とは言えない感じです。関数型言語だと大分マシにはなるけど、根本的解決じゃ無い気がします。

エラー処理も、結構問題です。メソッド内で起こったエラーをコールバック内に伝える必要があるため、必然的にオブジェクトを引き回す必要が有ります。

かと言って条件引数引き回すのもなんだかなぁ…。

jemallocの_malloc_preforkのバグ?

前エントリの件に関連して、glibcのmallocはpthread_atforkを呼んでるから大丈夫だよね的な話がkosakiブログに追記されていたので、他のmallocはどうなんだろうとjemallocを読んでみた。で、バグっぽいのを発見。ソースは以下。

ここでpthread_atforkを呼んでいる。

以下のmalloc_prefork関数が呼ばれるのだが、arenas_lockをunlockしている。

malloc_preforkがarenas_lockをunlockした瞬間に、他のスレッドがlockして解放しないままforkに到達したら、malloc_postforkでデッドロックする気がする。

P.S
バグ報告しました。

Java ProcessBuilderでデッドロック

id:nobu-qが踏んだバグ。Twitterにて、kosaki先生に凄く色々アドバイスを頂いた。革命の日々の1000エントリ目のネタゲット!

やりたいこととしては、C++のマルチスレッドプログラムから、HDFS(Hadoop Distributed File system)にアクセスしたい。そのために、libhdfsを使用している。

HadoopはJavaで記述されているために、libhdfsは内部でJavaのコードを呼び出している。このJavaのクライアントライブラリが、ユーザー名などを取得するために”whoami”コマンドを呼び出しており、fork(2)を行う。その際にデッドロックが起きていた。

コードの階層は次のようになる。mallocの実装には、tcmalloc 1.2を使用していた。

C++ Server
  C++ libhdfs
    Java HDFSClient
      Java ProcessBuilder
        JavaVM
          JavaVM C Layer
            tcmalloc

デッドロックが起こっている箇所は、tcmallocの内部だった。よくよく調べてみると、Java VMがfork(2)とexec(2)の間に、親プロセスが開いている全てのファイルディスクリプタを閉じるために/proc/self/fdをopendir(3)している。ここでmallocが呼ばれている。

- UNIXProcess_md.c
- bug 6336770

最初は、tmallocがpthread_atforkでmutexをきちんと処理していないので、こちらが悪いと思っていた。が、kosaki先生によるとそもそもfork(2)
とexec(2)の間ではasync-signal safeな関数しか呼んではいけないらしい(これはPOSIXの仕様???)。mallocの実装は関係が無い。

解決策としては、まずアプリを動かすためだけなら、Hadoop側を改変してProcessBuilderを使わないようにすれば良い。

JVMの方を直すには、一番理想的にはFD_CLOSEEXECを使う方法だけど、これは変更範囲が大きそうだし漏れが有りそう。

なので、async-signal safeな関数だけを用いて、現在開いている全てのファイルディスクリプタ番号を取得する方法が必要となる。で、どうするかを今調べているところ。SolarisとかBSD系でも動かないといけないので、どうしたもんかなあ。

Home > Uncategorized Archive

お薦め本
広告
Archives
Categories

Return to page top