DBM,File Readはどちらが早いか比較してみた。 †たとえば、1kくらいのファイルが、ひとつのディレクトリーに大量にあった場合、ファイルリードが遅くなってくし、大量にiノードを消費してしまう。それを防ぐために、たとえば、20万ファイルくらい、同一のディレクトリにあった場合、それをファイルとして保存せずに、ひとつにDBMにkey=ファイル名、value=ファイル内容にしてしまうことも可能だ。 複数のファイルをひとつのDBMに格納した場合、速度低下はあるのだろうか? 28万ファイルをひとつのDBMに突っ込んでみた。 †28万ファイルのxmlをひとつのDBMにつっこんみた 大体1Gぐらいの大きさ。dbmはdbmhashである。 key=filename value=fileの内容になっている。 DBM,ファイルリードを比べてみる。 †time=5851 func=<function gen_smlist at 0xb7cc54fc> smidsize=17979 time=174842 func=<function benchmark_dbm at 0xb7cbf7d4> time=269485 func=<function benchmark_file at 0xb7cc548c> 178秒(DBM)対269秒(FileRead)になっている。大体、2/3位になる。 結論 †小さなファイルをたくさん使う場合は、ファイルをそのまま保存するのではなく、DBMに入れるのもあり。 ソース †#!/usr/bin/python # -*- coding:utf-8 -*- import anydbm from glob import glob import os import json import time import random src='../nicoran-data/thumbinfo/*.xml' json_src='../nicoran-data/json/*.json' src_dir='../nicoran-data/thumbinfo/' def import_dbm(): l=glob(src) dbm=anydbm.open('thumbinfo.dbm','c') for i,f in enumerate(l): smid=os.path.basename(f).split('.')[0] dbm[smid]=open(f).read() if i%1000==0: print i,smid,f dbm.close() def import_test(): dbm=anydbm.open('thumbinfo.dbm','r') print dir(dbm) k=dbm.items() print len(k) def time_profile(f): def inner_time(*args,**keys): t1=time.time() r=f(*args,**keys) t1=time.time()-t1 print 'time=%d func=%s' % (t1*1000,f) return r return inner_time @time_profile def benchmark_dbm(smlist): dbm=anydbm.open('thumbinfo.dbm','r') for smid in smlist: r=dbm[smid] len(r) dbm.close() @time_profile def benchmark_file(smlist): for smid in smlist: smid=smid.encode('utf-8') smfile=src_dir+smid+'.xml' if os.path.isfile(smfile): a=open(smfile).read() k=len(a) @time_profile def gen_smlist(json_src): smlist=set() jds=glob(json_src) random.shuffle(jds) for jd in jds[:10]: jd=json.loads(open(jd).read()) for a in jd: for l in a['ranklist']: smid=l['smid'] smlist.add(smid.encode('utf-8')) return smlist def main(): #import_dbm() #mport_test() smlist=gen_smlist(json_src) print 'smidsize=%d' % len(smlist) benchmark_dbm(smlist) benchmark_file(smlist) if __name__=='__main__':main() |