2011年3月26日土曜日

Pythonからmemcachedに大量データをsetしてみた

Pythonからmemcachedに対して大量データをsetしてみました。
OSはFedora13です。

①memcachedのinstall
yum install memcached

②memcachedの起動
memcached -d
...因みにrootユーザでは起動出来ません。

③Python用ドライバのinstall
easy_install python-memcached

これで準備完了です。

次に以下のようなコードを実行します。

--------------------------------------------------------------
#!/usr/bin/env python
import csv
import memcache
import time

if __name__ == '__main__':
    start=time.time()
    mc = memcache.Client(['localhost:11211'])
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        mc.set(str(row[0]),row[1])
    print time.time()-start
--------------------------------------------------------------

実行したところ、100万行のsetが完了するのに、130sかかりました。

期待したほどのパフォーマンスは出ませんでした。
memcachedという名の通り、DISKへのアクセスは全く発生しないはず・・・。なんですが。

因みに、、今までの実行結果を振り返ると、
Java+PostgreSQL → 130s
Java+Sqlite3 → 19s
Python + Sqlite3 → 28s

PythonとJavaを速度比較してもあまり意味は無いかも知れませんが、上記からはmemcachedとPostgreSQLの速度はほとんど変わらないという事になってしまいます。これはどういう事でしょうか?

私は、クライアントアプリとmemcachedプロセス間の通信がオーバーヘッドになっているものと考え、上記ソースを以下のように修正し、1000件分まとめてsetするようにしました。

--------------------------------------------------------------
#!/usr/bin/env python
import csv
import memcache
import time

if __name__ == '__main__':
    cnt=0
    d={}
    start=time.time()
    mc = memcache.Client(['localhost:11211'])
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        d[str(row[0])] = row[1]
        cnt = cnt+1
        if cnt % 1000 == 0:
            mc.set_multi(d)
            d={}
            cnt=0
    print time.time()-start
--------------------------------------------------------------


上記ソースの場合には100万件のsetに47s程度となり、かなり高速化されました。

自身の経験ではJavaでのバッチ更新(addbatch)とかは使った事は無いのですが、大量の更新事にはかなり高速化に寄与しそうですね。また、SQLiteやH2はプロセス間通信が無い為、大量更新事には非常に高速に動作するというのも納得です。