Entries tagged “eventlet”

eventlet kqueue hub

written by shn, on Jan 29, 2010 2:14:00 PM.

先日のAppleのイベント用にこんなのを作って、動かしたりしてたいました。

中身はテキトーに書いたeventletベースCometサーバをFreeBSDで動かしてるのですが、eventletはkqueueのhubが無いのでちょっと負荷が心配になった。ので、kqueueのhubをでっち上げた。例によってテストは無いけど、一晩動いてたのでこの方向でいいのかしら。

http://gist.github.com/287764

kqueueバージンだったので、誰か優しく手ほどきしてください。

eventletでCometサーバ

written by shn, on Jan 17, 2010 6:05:00 PM.

eventletづいてるので、Cometサーバを書いてみたよ。

tinycomet.py at master from shnjp's tinycomet - GitHub

eventlet.wsgiを使って、200行ぐらいで簡単なのが書けました。楽しいですね。

使い方

python tinycomet.pyで起動して、 /update/<UUID>にPOSTするとデータを作成

% curl -v 'http://127.0.0.1:8090/update/hogehoge' -d mogemoge
...
< HTTP/1.1 201 Created
< X-Tc-Timestamp: 2
< Content-Length: 0
...

受け取るには、/wait/<UUID>

% curl -v 'http://127.0.0.1:8090/wait/hogehoge'
...
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< X-Tc-Timestamp: 4
< Content-Length: 7
...
mogemoge

waitにsince=<timestamp>をつけると、その時間になるまで待ちます。 各レスポンスのヘッダにあるX-TC-Timestampが、そのデータの最終更新時刻になります。 timestampは論理時間なので、実世界の時刻とは関係ありません

% curl 'http://127.0.0.1:8090/wait/hogehoge?since=4' &
[1] 97027
# waitに入る
% curl -v 'http://127.0.0.1:8090/update/hogeoge' -d fugafuga
fugafuga[1] + done ....

ほかに、waitにtimeout=[timeout:float]を与えると、timeout秒待って408 Request Timeoutを返します。

また、updateにfinished=1を与えると、次のwaitが終わった後にデータを消します。またcontent_type=[mimetype]でContent-Typeを指定できます。デフォルトはapplication/octet-stream

いろいろ引っかかったところ

event(pyevent)はだめくさい

eventletのdefault hubからthread safeじゃないという理由でpyeventが外されていたのだけど、今回はsingle threadなので試してみた。 しかしうまくimport出来ないので諦め。trunkも、配布バージョン(2007年!!)もだめじゃった。

python2.6からkqueueが使えるそうなので、自分でHubを書くのがよいのかな。eventlet自体もtrunkは結構変わっているので見ないといけなさげ

WaitForMultipleObjectsがやりたい

waitのところは、グローバルなConditionを作って

# wait側
with _update_lock:
    while data.last_update <= since:
        _update_lock.wait(timeout)

# update側
with _update_lock:
    _update_lock.notify_all()

とやっているので、捌くdataの数が増えると破綻すると思う。dataごとにイベントを持たせて、WaitForMultipleObjects()的なことがしたいのだけど、この枠組みではどうやるんだろう。オシエテエライヒト

/wait_multiはmultipart/*を吐くコードを書くのが面倒なので実装していない。

eventletでgearman worker

written by shn, on Jan 16, 2010 8:45:00 PM.

eventletっていうライブラリが僕好みの匂いを発していたので遊んでいる。 gearmanを使って、ブログのURLを与えたらそこのFeedのリストを返すってWorkerを書いていたので、それをeventlet化してみよう。

まず、gearmanのeventlet化、gearmanのライブラリにはpure-pythonのやつを使っていたのでさくっと行けた。

green_gearman.py

from eventlet import patcher
from eventlet.green import socket, select

for mod in ['worker', 'connection']:
    patcher.inject('gearman.%s' % mod, globals(),
        ('socket', socket),
        ('select', select)
    )
del patcher

eventletにはpatcherというざっくりしたモジュールがあって、これを使うと指定したモジュールのglobalsを置き換えてくれる。これでいいんかなっていうぐらい簡単。

試しにecho serverを書いてみる。

from eventlet import coros, api
from green_gearman import GearmanWorker

def echo_func(job):
    print api.getcurrent(), job.arg
    time.sleep(5.)

def main():
    pool = coros.CoroutinePool(max_size=200)
    waiters = []

    for idx in range(10):    
        worker = GearmanWorker(['0.0.0.0:4730'])
        worker.register_function('echo', echo_func)

        waiters.append(pool.execute(worker.work))

    for w in waiters:
        w.wait()
main()

gearmanのprotocolは同時に1ジョブしか処理できないっぽいので、とりあえず10個ぐらい突っ込んでみる。 gearman -h localhost -p 4730 -s -f echo hogehogeを20個ぐらい飛ばしてみた所、

<greenlet.greenlet object at 0x804137f30> hogehoge
<greenlet.greenlet object at 0x804127c90> hogehoge
<greenlet.greenlet object at 0x804137db0> hogehoge
<greenlet.greenlet object at 0x804137e10> hogehoge

ってなってるので、なんかまぁそれっぽくなってる気がする。こんなコードじゃよくわからんな… これで良いのでしょうか。

さて肝心のWorkerもこれにのせたいのだが、urllib2を使っていたので、代わりにfrom eventlet.green import urllib2に代えるだけっぽい(まだやってない…)。

んでつらつらコード見てたんだが、今のところ(eventlet 0.9.2)はlibeventサポートがdisabledされているようで、ちょっとがっかり。

eventlet化する場合、全てのIOをこれにしないとブロックが発生してみんな止まることになっちゃうのだけど、MySQL周りとかをeventlet化するのはめんどくさそうなのでアレでアレしてアレですね。