첫째, 일반적으로 프로토콜, 라이브러리 등의 주요 새로운 버전이 크게 개선 된 것이 놀랄만 한 것은 아닙니다. 그렇지 않으면 왜 누군가가 그들을 창조하기 위해 모든 일을 성가 시게 했습니까?
하지만 당신은 아마 구체적인 것을 찾고 있습니다.
우리가 무엇에 들어가기 전에 큰 문제는 이 pickletools.dumps
덤프에서하지 비교 프로토콜이 프로토콜 3, 당신이 비교하는 프로토콜 0 및 프로토콜 3.주의 마지막 줄이라는 것이다 아래 : highest protocol among opcodes = 2
. 2
대신 0
이 표시되면 프로토콜 0을 사용하고 있음을 의미합니다. 프로토콜 0은 인간의 가독성 (물론 최소한 pickletools
과 같은 라이브러리가없는 사람의 디버깅 가능성)을 위해 설계되었지만 컴팩트하지는 않습니다. 특히 인쇄 할 수없는 ASCII 바이트를 백 슬래시 이스케이프 처리하여 대부분을 4 자로 확장합니다.
그래서 왜 2 대신 0이 나옵니까? 역 호환성 때문에 가장 높은 프로토콜이 기본값이 아니기 때문입니다. 기본값은 2.x에서는 0이고 3.x에서는 3입니다. 2.7 및 3.4에 대한 문서를 참조하십시오.
pickle.dumps(msg, protocol=pickle.HIGHEST_PROTOCOL)
(또는 단지 protocol=-1
)으로 코드를 변경하면 0과 3 대신 2와 4가됩니다. 2.x는 여전히 3.x보다 클 것입니다. 이유는 다음과 같습니다 , 그러나 당신이 지금보고있는 것과 동일한 척도 근처에 아무 것도 없습니다.
패리티를 원한다면 프로토콜 -2 결과가 충분히 압축되어 있으면 protocol=2
을 명시 적으로 사용할 수 있습니다.
2 또는 3으로 명시 적으로 가고 싶다면 은 직접 글쓰기 방법이 없지만 protocol=min(3, pickle.HIGHEST_PROTOCOL)
은 그렇게 할 것입니다.
pickletools
모듈 (상기 문서에 링크 된 소스 코드에 주석)가 쉽게 차이를 탐구 할.
은 이제 쉽게 볼 수 있도록, 짧은 문자열을 사용하자 :
>>> t = (1, string.ascii_lowercase.encode('ascii'))
>>> p2 = pickle.dumps(t, protocol=2)
>>> p3 = pickle.dumps(t, protocol=3)
>>> len(p2), len(p3)
78, 38
그래서, 명백한 차이가 아직도있다.
이제 피클의 내용을 살펴 보겠습니다. 프로토콜이 개 상점,
>>> pickletools.dis(p2)
0: \x80 PROTO 2
2: K BININT1 1
4: c GLOBAL '_codecs encode'
20: q BINPUT 0
22: X BINUNICODE 'abcdefghijklmnopqrstuvwxyz'
53: q BINPUT 1
55: X BINUNICODE 'latin1'
66: q BINPUT 2
68: \x86 TUPLE2
69: q BINPUT 3
71: R REDUCE
72: q BINPUT 4
74: \x86 TUPLE2
75: q BINPUT 5
77: . STOP
highest protocol among opcodes = 2
당신이 볼 수 있듯이 (당신은 아마 자신의 통역에 pickletools.dis(p2, annotate=1)
을 사용하고자 하겠지만, 화면의 가장자리 오프 정보 스크롤의 대부분 때문에, 그 ... 여기 유용 아니다) bytes
은 유니 코드 문자열과 코덱으로 구성됩니다. 구체적으로 프로토콜 2.
에 존재하지 않았던 새로운 연산 코드를 사용하여 bytes
대상으로
>>> pickletools.dis(p3)
0: \x80 PROTO 3
2: K BININT1 1
4: C SHORT_BINBYTES b'abcdefghijklmnopqrstuvwxyz'
32: q BINPUT 0
34: \x86 TUPLE2
35: q BINPUT 1
37: . STOP
highest protocol among opcodes = 3
...하지만 프로토콜 3 저장합니다 :
의 BINUNICODE
가족 opcodes는 유니 코드 문자열을 취하여 길이 접두사 UTF-8로 저장합니다.
opcode의 BINBYTES
패밀리는 바이트 문자열을 가져 와서 길이 접두사로 저장합니다. 프로토콜 1, 2 BINBYTES
, bytes
이로 저장하지 않아도
때문에 효과의 인수로 b.decode('latin-1')
및 u'latin-1'
의 결과 _codecs.encode
를 호출.
이렇게하면 4030 바이트의 고정 오버 헤드 (내 p2
과 p3
사이의 차이를 설명 함)가 추가됩니다. 왜 라틴어 1을 선택해야할까요? 모든 바이트를 단일 유니 코드 문자로 매핑하는 가장 간단한 코덱이기 때문입니다.
더 중요한 것은 비 ASCII 바이트는 대부분 2 바이트의 UTF-8이 될 것입니다. 랜덤 바이트의 경우 총 오버 헤드가 약 51 %입니다.
이
BINBYTES
꽤 유사하다 나중에
BINSTRING
프로토콜 1을 입력하고,하지만 그것은 거의 결코 유용하지 않는 기본 인코딩, 바이트를
를 저장으로 정의되어 있음을 참고. 2.x에서는 실제로 차이를 만들지 않을 것입니다. 왜냐하면 여러분은 decode
이겠지만 str
을 얻지는 않을 것입니다.하지만 제 생각에 2.6+는 3.x 호환성을 위해 사용하지 않을 것입니다.
문자열에 repr
ASCII 인코딩을 저장하는 프로토콜 0으로 거슬러 올라간 STRING
유형도 있습니다. 나는 이것이 프로토콜 1 이상에서 사용 된 적이 없다고 생각합니다. 물론 이것은 인쇄 할 수없는 ASCII 바이트를 2 또는 4 바이트 백 슬래시 이스케이프로 날려 버릴 수 있습니다.
해당 5933 바이트를 재현 할 수 없습니다. 난 임의의 값으로 시도 할 때, 나는 3000 바이트 이상을 얻었고, 병적 인 것을주기 위해서도 (파이썬 2.7이나 3.4에서) 4K 이상을 얻을 수는 없다. 어쩌면 특별한 경우 라틴 -1 인코딩 BINUNICODE 이외의 것을 사용하고 있을까요? 어딘가에 바이트를 덤프 할 수 있다면 (또는'pickletools'으로 직접 보아라.) 나는 무엇이 다른지 궁금 할 것이다. – abarnert
또한 피클 포맷 2로 3.4에서 얻은 것을 테스트 했습니까? 같은 절임 형식으로 2.7에 들어있는 것과 같은가요? ('bytearray'를 사용하면, 두 언어 모두 기본적으로 같은 타입입니다. 3.4에서는'bytes', 2.7에서는'str'과 반대가됩니다.) – abarnert
@abarnert 그것의 라틴 -1 인코딩 된 BINUNICODE를 사용합니다. 내 데이터는 간단한 정수 (2 바이트) [int (math.sin)에서 생성]의 샘플 스트림입니다 (http://puu.sh/cn9bB/6a28d0d469.png). 나는 각 패킷에 1024 샘플 (2048 바이트)의 덩어리를 보낸다. 2.7에서 스크립트를 실행할 때 모든'b ""바이트 리터럴을 남겨 두었습니다. 실제로 2.7에서 str으로 변환됩니다. 나는 2.7 바이트에 해당하는 3.4 바이트가'bytearray'라는 것을 알지 못했다. 3.4에서 중요한 성능 저하없이 'bytearray'를 사용할 수 있다는 의미입니까? 각면에서 호환 가능한 코드를 사용하는 것이 좋을 것입니다. –