Published On: 1970-01-01|Last Updated: 1970-01-01|Categories: Uncategorized|
テンプレートエンジンの最適化をした際のノウハウ。

  • 文字列操作がかなりのコストを占める。
    • basestring.join, basestring.encode, basestring.decode は遅い。簡単なテンプレートでは実行時間の過半をこれらが占めることもある。
    • str += str は list.append や list.extend より遅い。
    • 引数を多く取れれば確実に list.extend の方が list.append より早い。ただし list.append -> cStringIO.StringIO.write のような単純な置換はできなくなる。
  • 当然だが、__import__(‘xml.sax.saxutils’).sax.saxutils.escape と呼ぶよりも from xml.sax.saxutils import escape してキャッシュした方がずっと速い。名前空間が汚染されると捉えるか、速度を優先するかはデザイン次第。
  • 関数呼び出しのコストは他の部分に比べればほぼ無視出来る。

テンプレートエンジンのベンチマークは上記のコストをいかに回避するかのテクニックを競っているようなもので、当てに出来るかは疑わしい。どんなに速くてもテンプレートの書き方次第で優位性は消えてしまう。PyPy とかの速い処理系に期待したほうがいい。

あと適当に文字列処理のコスト↓

import timeit
N = 1000
def bench(name, setup, stmt):
bench = timeit.Timer(stmt, setup)
print('|*%s|%.10f|' % (name, bench.timeit(N)))
import sys
print(sys.version)
bench('str +=', '_ = ""', '_ += " " * 1000')
bench('[] +=', '_ = []', '_ += [" " * 1000]')
bench('append', '_ = [].append', '_(" " * 1000)')
bench('extend', '_ = [].extend', '_((" " * 1000, ))')
bench('array.array("c").fromstring',
'import array; _ = array.array("c").fromstring', '_(" " * 1000)')
bench('cStringIO.StringIO().write',
'from cStringIO import StringIO; _ = StringIO().write', '_(" " * 1000)')
bench('"".join', '_ = [" " * 1000] * 1000', '"".join(_)')
bench('array.array("c").tostring',
'import array; _ = array.array("c"); _.fromstring(" " * 1000 * 1000)',
'_.tostring()')
bench('cStringIO.StringIO().getvalue',
'from cStringIO import StringIO; _ = StringIO(); _.write(" " * 1000 * 1000)',
'_.getvalue()')

>python bench.py

2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)]

str += 0.0596243883
[] += 0.0008418275
append 0.0006185779
extend 0.0006430312
array.array(“c”).fromstring 0.0503778714
cStringIO.StringIO().write 0.0015428220
“”.join 0.5401027310
array.array(“c”).tostring 0.5463220201
cStringIO.StringIO().getvalue 0.5506574994

>pypy bench.py

2.7.1 (930f0bc4125a, Nov 27 2011, 11:58:57)

[PyPy 1.7.0 with MSC v.1500 32 bit]
str += 0.8409847253
[] += 0.0022026083
append 0.0011542863
extend 0.0013141384
array.array(“c”).fromstring 0.0230599138
cStringIO.StringIO().write 0.0046778255
“”.join 1.4231829048
array.array(“c”).tostring 4.0303220907
cStringIO.StringIO().getvalue 0.0004813677

>pypy –jit off bench.py

2.7.1 (930f0bc4125a, Nov 27 2011, 11:58:57)

[PyPy 1.7.0 with MSC v.1500 32 bit]
str += 0.5654540095
[] += 0.0015179159
append 0.0012208536
extend 0.0011954946
array.array(“c”).fromstring 0.0187525104
cStringIO.StringIO().write 0.0043712536
“”.join 1.0814593729
array.array(“c”).tostring 3.9519700981
cStringIO.StringIO().getvalue 0.0004741223

関連