2017-12-19 6 views
2

引数を使用してpickle.dumpsで使用されるプロトコルを指定した場合、または希望のプロトコルバージョンの場合は モンキーパッチpickle.DEFAULT_PROTOCOLを指定した場合、速度に関してかなり大きな違いが生じることに気がつきましたが、 。サルパッチDEFAULT_PROTOCOLによるpickle.dumpsのパフォーマンスが向上しましたか?

のPython 3.6で

pickle.DEFAULT_PROTOCOLは3であり、それはより速く DEFAULT_PROTOCOL 4を設定する代わりに引数としてprotocol=4を通過しているように見える特定の長さまで pickle.HIGHEST_PROTOCOLオブジェクト4.

あります。 pickle.dumps(packet_list_1, protocol=4)と呼び出すと733ナノ秒を要しながらpickle.dumps(packet_list_1)を呼び出すことによって、長さ1のリストを4にpickle.DEFAULT_PROTOCOLを設定し、酸洗 と例えば私のテストにおいて

は、通過のための驚異〜52%の速度ペナルティ、481ナノ秒を要します(デフォルトでは4に設定されていました)。

""" 
    (stackoverflow insists this to be formatted as code:) 

    pickle.DEFAULT_PROTOCOL = 4 
    pickle.dumps(packet) vs pickle.dumps(packet, protocol=4): 

    (stackoverflow insists this to be formatted as code:) 
    For a list with length 1 it's 481ns vs 733ns (~52% penalty). 
    For a list with length 10 it's 763ns vs 999ns (~30% penalty). 
    For a list with length 100 it's 2.99 µs vs 3.21 µs (~7% penalty). 
    For a list with length 1000 it's 25.8 µs vs 26.2 µs (~1.5% penalty). 
    For a list with length 1_000_000 it's 32 ms vs 32.4 ms (~1.13% penalty). 
    """ 

は、私がこれまでテストした すべてであるインスタンス、リスト、dictsと配列のため、この動作を、見つけました。この効果は、オブジェクトのサイズとともに減少します。 dictsについて

Iは、(一意の整数値を有する)長さ10 ** 6辞書用 それは引数(269ms)として明示的に パスプロトコル= 4に高速だように、反対に、いくつかの点で回転効果に気づいよりデフォルトでは4(286ms)に設定されています。ピクルスソース上Glimpsing

""" 
pickle.DEFAULT_PROTOCOL = 4 
pickle.dumps(packet) vs pickle.dumps(packet, protocol=4): 

For a dict with length 1 it's 589 ns vs 811 ns (~38% penalty). 
For a dict with length 10 it's 1.59 µs vs 1.81 µs (~14% penalty). 
For a dict with length 100 it's 13.2 µs vs 12.9 µs (~2,3% penalty). 
For a dict with length 1000 it's 128 µs vs 129 µs (~0.8% penalty). 
For a dict with length 1_000_000 it's 306 ms vs 283 ms (~7.5% improvement). 
""" 

、何も 、このような変動を引き起こすかもしれないもの、私の目を打つん。

この予期しない動作はどのように説明できますか?

はpickle.DEFAULT_PROTOCOLを設定する代わりに、速度向上を活用するために、引数として プロトコルを渡すための任意の注意点はありますか?

(Pythonの3.6.3、IPython 6.2.1、Windows 7でIPythonのはtimeit魔法で時限)

いくつかのサンプルコードダンプ:

# instances ------------------------------------------------------------- 
class Dummy: pass 

dummy = Dummy() 

pickle.DEFAULT_PROTOCOL = 3 

""" 
>>> %timeit pickle.dumps(dummy) 
5.8 µs ± 33.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
>>> %timeit pickle.dumps(dummy, protocol=4) 
6.18 µs ± 10.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
""" 
pickle.DEFAULT_PROTOCOL = 4 
""" 
%timeit pickle.dumps(dummy) 
5.74 µs ± 18.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
%timeit pickle.dumps(dummy, protocol=4) 
6.24 µs ± 26.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
""" 

# lists ------------------------------------------------------------- 
packet_list_1 = [*range(1)] 

pickle.DEFAULT_PROTOCOL = 3 
""" 
>>>%timeit pickle.dumps(packet_list_1) 
476 ns ± 1.01 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
>>>%timeit pickle.dumps(packet_list_1, protocol=4) 
730 ns ± 2.22 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
""" 
pickle.DEFAULT_PROTOCOL = 4 
""" 
>>>%timeit pickle.dumps(packet_list_1) 
481 ns ± 2.12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
>>>%timeit pickle.dumps(packet_list_1, protocol=4) 
733 ns ± 2.94 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
""" 
# -------------------------- 
packet_list_10 = [*range(10)] 

pickle.DEFAULT_PROTOCOL = 3 

""" 
>>>%timeit pickle.dumps(packet_list_10) 
714 ns ± 3.05 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
>>>%timeit pickle.dumps(packet_list_10, protocol=4) 
978 ns ± 24.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
""" 
pickle.DEFAULT_PROTOCOL = 4 
""" 
>>>%timeit pickle.dumps(packet_list_10) 
763 ns ± 3.16 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
>>>%timeit pickle.dumps(packet_list_10, protocol=4) 
999 ns ± 8.34 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 
""" 
# -------------------------- 
packet_list_100 = [*range(100)] 

pickle.DEFAULT_PROTOCOL = 3 

""" 
>>>%timeit pickle.dumps(packet_list_100) 
2.96 µs ± 5.16 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
>>>%timeit pickle.dumps(packet_list_100, protocol=4) 
3.22 µs ± 18.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
""" 
pickle.DEFAULT_PROTOCOL = 4 
""" 
>>>%timeit pickle.dumps(packet_list_100) 
2.99 µs ± 18.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
>>>%timeit pickle.dumps(packet_list_100, protocol=4) 
3.21 µs ± 9.11 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 
""" 
# -------------------------- 
packet_list_1000 = [*range(1000)] 

pickle.DEFAULT_PROTOCOL = 3 

""" 
>>>%timeit pickle.dumps(packet_list_1000) 
26 µs ± 105 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
>>>%timeit pickle.dumps(packet_list_1000, protocol=4) 
26.4 µs ± 93.9 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
""" 
pickle.DEFAULT_PROTOCOL = 4 
""" 
>>>%timeit pickle.dumps(packet_list_1000) 
25.8 µs ± 110 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
>>>%timeit pickle.dumps(packet_list_1000, protocol=4) 
26.2 µs ± 101 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
""" 
# -------------------------- 
packet_list_1m = [*range(10**6)] 

pickle.DEFAULT_PROTOCOL = 3 

""" 
>>>%timeit pickle.dumps(packet_list_1m) 
32 ms ± 119 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) 
>>>%timeit pickle.dumps(packet_list_1m, protocol=4) 
32.3 ms ± 141 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) 
""" 
pickle.DEFAULT_PROTOCOL = 4 
""" 
>>>%timeit pickle.dumps(packet_list_1m) 
32 ms ± 52.7 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) 
>>>%timeit pickle.dumps(packet_list_1m, protocol=4) 
32.4 ms ± 466 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) 
""" 

答えて

2

はのリターンによってあなた%のはtimeit結果を再編成してみましょう値%timeit結果がよく対応方法

| DEFAULT_PROTOCOL | call         | %timeit   | returns                              | 
|------------------+-----------------------------------------+-------------------+------------------------------------------------------------------------------------------------------------------------------| 
|    3 | pickle.dumps(dummy)      | 5.8 µs ± 33.5 ns | b'\x80\x03c__main__\nDummy\nq\x00)\x81q\x01.'                    | 
|    4 | pickle.dumps(dummy)      | 5.74 µs ± 18.8 ns | b'\x80\x03c__main__\nDummy\nq\x00)\x81q\x01.'                    | 
|    3 | pickle.dumps(dummy, protocol=4)   | 6.18 µs ± 10.4 ns | b'\x80\x04\x95\x1b\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x05Dummy\x94\x93\x94)}\x94\x92\x94.'     | 
|    4 | pickle.dumps(dummy, protocol=4)   | 6.24 µs ± 26.7 ns | b'\x80\x04\x95\x1b\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x05Dummy\x94\x93\x94)}\x94\x92\x94.'     | 
|    3 | pickle.dumps(packet_list_1)    | 476 ns ± 1.01 ns | b'\x80\x03]q\x00cbuiltins\nrange\nq\x01K\x00K\x01K\x01\x87q\x02Rq\x03a.'              | 
|    4 | pickle.dumps(packet_list_1)    | 481 ns ± 2.12 ns | b'\x80\x03]q\x00cbuiltins\nrange\nq\x01K\x00K\x01K\x01\x87q\x02Rq\x03a.'              | 
|    3 | pickle.dumps(packet_list_1, protocol=4) | 730 ns ± 2.22 ns | b'\x80\x04\x95#\x00\x00\x00\x00\x00\x00\x00]\x94\x8c\x08builtins\x94\x8c\x05range\x94\x93\x94K\x00K\x01K\x01\x87\x94R\x94a.' | 
|    4 | pickle.dumps(packet_list_1, protocol=4) | 733 ns ± 2.94 ns | b'\x80\x04\x95#\x00\x00\x00\x00\x00\x00\x00]\x94\x8c\x08builtins\x94\x8c\x05range\x94\x93\x94K\x00K\x01K\x01\x87\x94R\x94a.' | 

をお知らせ同じ戻り値を与える呼び出しをペアにします。

pickle.DEFAULT_PROTOCOLの値は、pickle.dumpsによって返される値には影響しません。 protocolパラメータが指定されていない場合、pickle.DEFAULT_PROTOCOLの値に関係なく、デフォルトのプロトコルは3です。

reason is here:それは_pickle、ピクルスモジュールのコンパイルされたバージョンをインポートに成功した場合

# Use the faster _pickle if possible 
try: 
    from _pickle import (
     PickleError, 
     PicklingError, 
     UnpicklingError, 
     Pickler, 
     Unpickler, 
     dump, 
     dumps, 
     load, 
     loads 
    ) 
except ImportError: 
    Pickler, Unpickler = _Pickler, _Unpickler 
    dump, dumps, load, loads = _dump, _dumps, _load, _loads 

pickleモジュールは_pickle.dumpspickle.dumpsを設定します。 _pickleモジュールは、デフォルトでprotocol=3を使用します。 );悲しい、ノーフリーランチここだから、

In [68]: pickle.DEFAULT_PROTOCOL = 3 

In [70]: pickle._dumps(dummy) 
Out[70]: b'\x80\x03c__main__\nDummy\nq\x00)\x81q\x01.' 

In [71]: pickle.DEFAULT_PROTOCOL = 4 

In [72]: pickle._dumps(dummy) 
Out[72]: b'\x80\x04\x95\x1b\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x05Dummy\x94\x93\x94)}\x94\x92\x94.' 
+0

:Pythonは_pickledumpsセットthe Python versionにあるインポートに失敗した場合にのみ:

def _dumps(obj, protocol=None, *, fix_imports=True): f = io.BytesIO() _Pickler(f, protocol, fix_imports=fix_imports).dump(obj) res = f.getvalue() assert isinstance(res, bytes_types) return res 

のみPythonのバージョン、_dumpspickle.DEFAULT_PROTOCOLの値に影響されますどうもありがとうございました! – Darkonaut

関連する問題