概要
Pythonで数億回の単位のループの中で何度も読み込まれる情報の取り扱いに際して、list, tuple, dict, bitシフトのうち、listを使うと一番良いことがわかったため、その結果をまとめる。なお、Pythonのバージョンは3.9.12を用いた。
追記: 環境依存でlistとtupleの実行速度が逆転したり、同じになったりする場合があるようです。
ただ、他の方からも指摘を受けましたが、この程度の差なら可読性を優先すればよいと思います(とはいえlistでよいですが)。
また、この差が影響するレベルのプログラムなら、そもそもPythonを使うべきではないかと思います。
結果
後述するプログラムで各処理に1億回アクセスした際の実行結果を先に示す。
list 2.5855608 s
tuple 2.8783302 s
dict 3.002389400000001 s
bit shift 4.6369679999999995 s
このように、listを用いた場合において、最も早い結果を示した。
実際に実行したプログラムが下記で、bit shiftの場合は
test = (b >> 2) & 0b11
と書くのが正確だが、速度比較の観点から省略している。
import time
def main():
i_max = 100000000
l = [1, 2, 3]
t = (1, 2, 3)
d = {0: 1, 1: 2, 2: 3}
b = 0b111001
start_time = time.perf_counter()
for _ in range(i_max):
test = l[1]
end_time = time.perf_counter()
print("list", end_time - start_time, "s")
start_time = time.perf_counter()
for _ in range(i_max):
test = t[1]
end_time = time.perf_counter()
print("tuple", end_time - start_time, "s")
start_time = time.perf_counter()
for _ in range(i_max):
test = d[1]
end_time = time.perf_counter()
print("dict", end_time - start_time, "s")
start_time = time.perf_counter()
for _ in range(i_max):
test = b >> 2
end_time = time.perf_counter()
print("bit shift", end_time - start_time, "s")
main()
考察
意外なことに、処理的には同じと思われるtupleとlistで速度差が生じた。
パフォーマンスの観点から、tupleを使うといい、とよく言われているが、それは生成時の話である。
しかも、生成時に巨大なlistやtupleを生成することはまずないため、実質的にtupleを用いる必要はないと思われる。
なお、メモリの観点からすると、tupleの方が優秀ではあるが、メモリを気にするサイズのtupleを生成することも少ないため、listを使うのが無難だろう。
個人的に知らなかったことであるが、bit shiftの計算は意外と遅いようで、dictへのアクセスよりも遅い結果となった。
結論
本ページでは膨大な繰り返しの中で使用するに適した複数要素を持つオブジェクトがlistであることを示した。