recently asked a question 큰 파이썬 오브젝트를 파일에 저장하는 방법은 다음과 같습니다. 이전에는 대용량 파이썬 사전을 문자열로 변환하고 write()
을 통해 파일에 쓰는 데 문제가있었습니다. 이제 나는 피클을 사용하고 있습니다. 그것은 작동하지만, 파일은 엄청나게 커 (> 5 GB). 나는 큰 파일들에 대한 경험이 거의 없다. 나는이 피클 파일을 메모리에 저장하기 전에 압축하는 것이 더 빠르거나 가능할지를 알고 싶었다.큰 파일을 파이썬에 저장하는 가장 빠른 방법
답변
데이터 직렬화를 구현할 때 파이썬 코드가 매우 느립니다. 순수 Python에서 Pickle에 해당하는 것을 만들려고하면, 느린 속도가 될 것입니다. 다행히도이를 수행하는 내장 모듈은 꽤 좋습니다.
cPickle
외에도 marshal
모듈이 훨씬 빠릅니다. 그러나 실제 파일 핸들이 필요합니다 (파일과 같은 오브젝트가 아님). import marshal as Pickle
수 있으며 차이점을 참조하십시오. 나는 당신이이보다 훨씬 빠른 사용자 지정 serializer를 만들 수 있다고 생각하지 않습니다 ...
나는 이것을 묻는 것이 정말로 벙어리지만, 왜 '직렬화'가 되는가? WOW는 피클보다 100 배 빠른 마샬링이다. marshal으로 쉽게 전환 할 수 있습니까? 아니면 대대적 인 정밀 검사가 필요합니까? – puk
데이터 구조를 스트림으로 덤프하는 것은 * serialization *입니다. cPickle/marshal (cPickle을 사용하고 있다고 생각했습니다)로 쉽게 전환 할 수 있습니다. –
아니요 나는 일반 피클 (ppickle?)을 사용하고있었습니다. 저는 방금 마샬과 피클 및 와우를 비교하는 간단한 테스트를 실시했습니다. 우리는 두 가지 차수의 차이를 이야기하고 있습니다. – puk
당신은 bzip2으로 데이터를 압축 할 수 있습니다
from __future__ import with_statement # Only for Python 2.5
import bz2,json,contextlib
hugeData = {'key': {'x': 1, 'y':2}}
with contextlib.closing(bz2.BZ2File('data.json.bz2', 'wb')) as f:
json.dump(hugeData, f)
로드를 다음과 같이 :
from __future__ import with_statement # Only for Python 2.5
import bz2,json,contextlib
with contextlib.closing(bz2.BZ2File('data.json.bz2', 'rb')) as f:
hugeData = json.load(f)
당신은 또한 거의 동일한 인터페이스와 zlib 또는 gzip를 사용하여 데이터를 압축 할 수 있습니다. 그러나 zlib와 gzip의 압축률은 모두 bzip2 (또는 lzma)보다 낮은 압축률입니다.
구문에 익숙하지 않지만 BZ2File을 메모리로 압축 한 다음 json (또는 피클을 가정합니다)을 사용하여 덤프 할 수 있습니다. – puk
@ 구문 어떤 구문을 사용합니까? 'with' 문은 파일이 닫혀 있는지를 확인하는 문법적 설탕입니다. 'f = bz2.BZ2File (...)'로 읽을 수 있습니다. 이것은 ** 상당한 양의 데이터를 메모리에 저장하지 않고 ** 좋은 일입니다. 데이터는 즉시 직렬화되고 압축되며 메모리 사용량 (OS 캐시 제외)은 메가 바이트보다 크게 커야합니다. – phihag
'with '접근법은 훨씬 적은 메모리를 사용합니다. 맞습니까? – puk
빠르게, 또는 수는, 이전의 [쓰기] 물론
이 피클 파일을 압축하는 것이 가능하지만 (메모리에 명시 적으로 압축 복사 할 수는 있습니다 시도 할 이유가 없습니다 적합하지 않은 경우) 을 작성하면 자동으로 표준 라이브러리 기능이 내장 된 표준 라이브러리 기능이 내장 된;
http://docs.python.org/library/gzip.html을 참조하십시오. 기본적으로, 당신은
gzip.GzipFile("output file name", "wb")
와 스트림의 특별한 종류를 만든 다음 (그 문제 또는 file(...)
) open(...)
로 만든 일반 file
처럼 정확히를 사용합니다.
나는 이것이 내가 쓰려고하는 것처럼 기본적으로 압축하려고 시도 할 것이라고 생각한다. – puk
Google의 ProtoBuffers을보세요. 오디오 - 비디오 파일과 같은 대용량 파일을 위해 설계되지는 않았지만이를 위해 설계되었으므로 객체 직렬화는 사용자의 경우처럼 잘 수행됩니다. 연습은 언젠가 파일의 구조를 업데이트해야 할 수도 있고, ProtoBuffers가이를 처리 할 수 있음을 보여줍니다. 또한 압축 및 속도면에서 매우 최적화되어 있습니다. 파이썬에 묶여 있지 않아도 자바와 C++이 잘 지원됩니다.
난 그냥 phihag의 대답에 확장 것입니다.
RAM의 크기에 근접하는 객체를 직렬화하려고하면이 표시되므로 serialize하려면 pickle/cPickle을 피해야합니다. BZ2 파일로 스트리밍하는 경우에도 마찬가지입니다. 제 경우에는 스왑 공간이 부족했습니다.
하지만 JSON (그리고 링크 된 기사에서 언급 한 HDF 파일과 유사)의 문제점은 데이터에서 dicts의 키로 사용되는 튜플을 직렬화 할 수 없다는 점입니다. 이것에 대한 훌륭한 해결책은 없습니다. 내가 찾을 수있는 최선의 방법은 튜플을 문자열로 변환하는 것이 었습니다. 튜플을 문자열로 변환하는 것이 었습니다.이 튜플은 자체 메모리를 필요로하지만 피클보다는 훨씬 적습니다. 요즘에는 json 라이브러리보다 훨씬 빠른 the ujson library을 사용할 수도 있습니다. 문자열 이루어지는 튜플
은 (더 쉼표가 없음 문자열 필요)
import ujson as json
from bz2 import BZ2File
bigdata = { ('a','b','c') : 25, ('d','e') : 13 }
bigdata = dict([(','.join(k), v) for k, v in bigdata.viewitems()])
f = BZ2File('filename.json.bz2',mode='wb')
json.dump(bigdata,f)
f.close()
하려면 튜플 재 작성 :
bigdata = dict([(tuple(k.split(',')),v) for k,v in bigdata.viewitems()])
다르게하는 경우를 예를 들어
bigdata2 = { (1,2): 1.2, (2,3): 3.4}
bigdata2 = dict([('%d,%d' % k, v) for k, v in bigdata2.viewitems()])
# ... save, load ...
bigdata2 = dict([(tuple(map(int,k.split(','))),v) for k,v in bigdata2.viewitems()])
피클 이상이 방법의 또 다른 장점은 JSON이의 bzip2 압축을 사용하는 경우 피클보다 훨씬 더 나은 압축하는 표시이다 : 당신의 키는 정수의 2 튜플이다.
메모리에 저장 하시겠습니까? – Cameron
@JBernardo 그건 너의 차가 고장 났을 때와 같이 부모님이 너가 갈 필요가있는 곳으로 달려 가서 부모님이 돌아올 때까지 대중 교통을 이용할 수있게 해달라고 말하는 것과 같다. –
하드 디스크에 보관하기. 하드 디스크에 5GB가 넘는 용량을 쓰기 위해서는 매우 오랜 시간이 걸린다 고 가정합니다. – puk