Pythonで一定長のリスト初期化にかかる時間の比較 | 忘れたらググればいい

2015年5月9日土曜日

Pythonで一定長のリスト初期化にかかる時間の比較

元ネタ

あなたのPythonを爆速にする7つの方法

あと時間計測ならば1回だけじゃなくて,何回か実行した平均を取った方がいい.

条件を揃えてやってみた

全要素が0のリストの生成

  • 空の配列に1つずつ0をappend (list_0_append)
  • リスト内包表記 (list_0_comp)
  • 乗算 (list_0_multi)
  • array (list_0_array)
  • rangeで作ったリストに0を代入 (list_0_range)

要素が[0, 1, ..., n-1]のリストの生成

  • 空の配列に1つずつ数値をappend (list_i_append)
  • リスト内包表記 (list_i_comp)
  • 全0のリストを作ったあとに代入 (list_i_multi)
  • array (list_i_array)
  • range (list_i_range)

実証スクリプト

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# bench.py
#
# Created by FUKUBAYASHI Yuichiro on 2015/05/09
# Copyright (c) 2015, FUKUBAYASHI Yuichiro
#
# last update: <2015/05/09 02:42:22>
#
import sys
from optparse import OptionParser
import time
from array import array
# list all 0
def list_0_append(n):
xs = []
for i in xrange(n):
xs.append(0)
return xs
def list_0_comp(n):
return [0 for i in xrange(n)]
def list_0_multi(n):
return [0] * n
def list_0_array(n):
return array('I', [0 for i in xrange(n)])
def list_0_range(n):
xs = range(n)
for i in xrange(n):
xs[i] = 0
return xs
# list i
def list_i_append(n):
xs = []
for i in xrange(n):
xs.append(i)
return xs
def list_i_comp(n):
return [i for i in xrange(n)]
def list_i_multi(n):
xs = [0] * n
for i in xrange(n):
xs[i] = i
return xs
def list_i_array(n):
return array('I', [i for i in xrange(n)])
def list_i_range(n):
return range(n)
# measure exec time
def exec_time(n, n_sample, func):
t = 0.0
for i in range(n_sample):
start = time.clock()
func(n)
end = time.clock()
t += (end - start)
return t / n_sample
def main(options, args):
n = options.n
n_sample = 5
print "--Python version--"
print sys.version
print
print "--list_0--"
for f in [list_0_append,
list_0_comp,
list_0_multi,
list_0_array,
list_0_range]:
print "%s(%d) in %f(s)" % (f.__name__,
n,
exec_time(n, n_sample, f))
print
print "--list_i--"
for f in [list_i_append,
list_i_comp,
list_i_multi,
list_i_array,
list_i_range]:
print "%s(%d) in %f(s)" % (f.__name__,
n,
exec_time(n, n_sample, f))
if __name__ == '__main__':
parser = OptionParser()
parser.add_option('-n', action='store', type='int', default=10000)
options, args = parser.parse_args()
main(options, args)
view raw bench.py hosted with ❤ by GitHub

結果

% python bench.py -n 1000000
--Python version--
2.7.9 (v2.7.9:648dcafa7e5f, Dec 10 2014, 10:10:46) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]

--list_0--
list_0_append(1000000) in 0.229992(s)
list_0_comp(1000000) in 0.087843(s)
list_0_multi(1000000) in 0.016838(s)
list_0_array(1000000) in 0.212526(s)
list_0_range(1000000) in 0.175999(s)

--list_i--
list_i_append(1000000) in 0.241931(s)
list_i_comp(1000000) in 0.112636(s)
list_i_multi(1000000) in 0.155012(s)
list_i_array(1000000) in 0.237255(s)
list_i_range(1000000) in 0.050963(s)

全要素0であっても乗算が一番速かった. [0, 1,...,n-1]の場合は,乗算よりリスト内包表記の方が速い.が,range(n)の方がもっと速かった.

pypyでもやってみた

pypy bench.py -n 1000000
--Python version--
2.7.9 (9c4588d731b7, Mar 23 2015, 16:20:40)
[PyPy 2.5.1 with GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)]

--list_0--
list_0_append(1000000) in 0.152410(s)
list_0_comp(1000000) in 0.014103(s)
list_0_multi(1000000) in 0.010896(s)
list_0_array(1000000) in 0.022531(s)
list_0_range(1000000) in 0.022315(s)

--list_i--
list_i_append(1000000) in 0.143897(s)
list_i_comp(1000000) in 0.014448(s)
list_i_multi(1000000) in 0.016995(s)
list_i_array(1000000) in 0.023090(s)
list_i_range(1000000) in 0.000005(s)

CPythonよりだいぶ速い.list_i_rangeは異常 (笑).

結論

全要素同じの場合は乗算,[0, 1,...,n-1]ならばrangeが速い. そしてpypy超速い (もちろんメモリやCPUの使い方まで比較してないので一概にpypyがいいとは言えない).