copy.deepcopy()とpickle経由のコピーの速度比較

pythonのcopy.deepcopy()とpickle経由のコピーの速度を比較した。
pythonのcopy.deepcopy()に死ぬほど時間がかかるなーと思っていたら、こんなQAを見つけた。

python - copy.deepcopy vs pickle - Stack Overflow

deepcopyよりも使える場面は減るが、pickle経由で新しいオブジェクトを作ったほうが速いことがあるらしい。
簡単に実験してみた。


case copy.copy() copy.deepcopy() pickle
1 0.64 ms 303.71 ms 6.14 ms
2 1.98 ms 1471.17 ms 65.49 ms
3 1.13 ms 3376.47 ms 177.26 ms
4 (3.14 ms) 7585.37 ms 326.24 ms
5 (0.54 ms) 244.45 ms 6.75 ms

それぞれのテストケースでコピーしている内容はソースコードを参照。
copyで結果が括弧つきになっているものはdeepcopyできていないケース。

どのケースでもpickleを使ったほうがdeepcopyよりも10倍以上早くなっている。
整数のリストをコピーするだけ(case 1)でも大きく差がついている。

なんでこんなに差がつくのか気になって、cpythonの実装を調べてみた。

def _deepcopy_list(x, memo, deepcopy=deepcopy):
    y = []
    memo[id(x)] = y
    append = y.append
    for a in x:
        append(deepcopy(a, memo))
    return y

(参照:cpython/copy.py at 3.8 · python/cpython · GitHub

listのコピーをappend連打で行っていた。
これは確かに時間がかかりそう。

一方、pickleの方はC言語で実装されているのでfor文がそこそこ高速に回せるということらしい。


なお、numpy.ndarrayなど高速な__deepcopy__が定義されているクラスなら、無難にdeepcopyするのが一番速いので注意。