[PYTHON] Python 3 - 4GB보다 큰 바이트 객체를 처리 할 수 있습니까?
PYTHONPython 3 - 4GB보다 큰 바이트 객체를 처리 할 수 있습니까?
이 주석과 참조 된 문서를 토대로, Python 3.4+의 Pickle 4.0+는 4GB보다 큰 바이트 객체를 피클 할 수 있어야합니다.
그러나 Mac OS X 10.10.4에서 python 3.4.3 또는 python 3.5.0b2를 사용하면 큰 바이트 배열을 피클 할 때 오류가 발생합니다.
>>> import pickle
>>> x = bytearray(8 * 1000 * 1000 * 1000)
>>> fp = open("x.dat", "wb")
>>> pickle.dump(x, fp, protocol = 4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument
내 코드에 버그가 있습니까? 아니면 설명서를 오해하고 있습니까?
해결법
-
==============================
1.다음은 문제 24658에 대한 간단한 해결책입니다. pickle.loads 또는 pickle.dumps를 사용하고 바이트 객체를 크기 2 ** 31 - 1 청크로 나누어 파일에서 가져 오거나 빠져 나오십시오.
다음은 문제 24658에 대한 간단한 해결책입니다. pickle.loads 또는 pickle.dumps를 사용하고 바이트 객체를 크기 2 ** 31 - 1 청크로 나누어 파일에서 가져 오거나 빠져 나오십시오.
import pickle import os.path file_path = "pkl.pkl" n_bytes = 2**31 max_bytes = 2**31 - 1 data = bytearray(n_bytes) ## write bytes_out = pickle.dumps(data) with open(file_path, 'wb') as f_out: for idx in range(0, len(bytes_out), max_bytes): f_out.write(bytes_out[idx:idx+max_bytes]) ## read bytes_in = bytearray(0) input_size = os.path.getsize(file_path) with open(file_path, 'rb') as f_in: for _ in range(0, input_size, max_bytes): bytes_in += f_in.read(max_bytes) data2 = pickle.loads(bytes_in) assert(data == data2)
-
==============================
2.코멘트에서 답을 요약하면 다음과 같습니다.
코멘트에서 답을 요약하면 다음과 같습니다.
네, 파이썬은 4GB보다 큰 바이트 객체를 피클 할 수 있습니다. 관찰 된 오류는 구현상의 버그로 인해 발생합니다 (Issue24658 참조).
-
==============================
3.pickle.load는 더 이상 거대한 파일을 더 이상 덤프하지 않으려 고합니다 (필자는 Python 3.5.2를 사용하고 있습니다). 그래서 엄밀히 말하면 pickle.dumps 만 제대로 작동해야합니다.
pickle.load는 더 이상 거대한 파일을 더 이상 덤프하지 않으려 고합니다 (필자는 Python 3.5.2를 사용하고 있습니다). 그래서 엄밀히 말하면 pickle.dumps 만 제대로 작동해야합니다.
class MacOSFile(object): def __init__(self, f): self.f = f def __getattr__(self, item): return getattr(self.f, item) def read(self, n): # print("reading total_bytes=%s" % n, flush=True) if n >= (1 << 31): buffer = bytearray(n) idx = 0 while idx < n: batch_size = min(n - idx, 1 << 31 - 1) # print("reading bytes [%s,%s)..." % (idx, idx + batch_size), end="", flush=True) buffer[idx:idx + batch_size] = self.f.read(batch_size) # print("done.", flush=True) idx += batch_size return buffer return self.f.read(n) def write(self, buffer): n = len(buffer) print("writing total_bytes=%s..." % n, flush=True) idx = 0 while idx < n: batch_size = min(n - idx, 1 << 31 - 1) print("writing bytes [%s, %s)... " % (idx, idx + batch_size), end="", flush=True) self.f.write(buffer[idx:idx + batch_size]) print("done.", flush=True) idx += batch_size def pickle_dump(obj, file_path): with open(file_path, "wb") as f: return pickle.dump(obj, MacOSFile(f), protocol=pickle.HIGHEST_PROTOCOL) def pickle_load(file_path): with open(file_path, "rb") as f: return pickle.load(MacOSFile(f))
-
==============================
4.바이트 연결을 수행하는 경우 2GB 청크로 파일을 읽는 데 필요한 메모리가 두 배가되고, pickle을로드하는 방식은 bytearray를 기반으로합니다.
바이트 연결을 수행하는 경우 2GB 청크로 파일을 읽는 데 필요한 메모리가 두 배가되고, pickle을로드하는 방식은 bytearray를 기반으로합니다.
class MacOSFile(object): def __init__(self, f): self.f = f def __getattr__(self, item): return getattr(self.f, item) def read(self, n): if n >= (1 << 31): buffer = bytearray(n) pos = 0 while pos < n: size = min(n - pos, 1 << 31 - 1) chunk = self.f.read(size) buffer[pos:pos + size] = chunk pos += size return buffer return self.f.read(n)
용법:
with open("/path", "rb") as fin: obj = pickle.load(MacOSFile(fin))
-
==============================
5.또한이 문제를 해결하기 위해 코드를 여러 번 반복했습니다. 말하자면이 경우에는 50.000 데이터를 계산해야하는데 tf-idf와 knf classfication을 수행해야합니다. 내가 50.000을 반복 실행하면 직접 "그 오류"가 발생합니다. 그래서,이 문제를 해결하기 위해 나는 그것을 덩어리로 만든다.
또한이 문제를 해결하기 위해 코드를 여러 번 반복했습니다. 말하자면이 경우에는 50.000 데이터를 계산해야하는데 tf-idf와 knf classfication을 수행해야합니다. 내가 50.000을 반복 실행하면 직접 "그 오류"가 발생합니다. 그래서,이 문제를 해결하기 위해 나는 그것을 덩어리로 만든다.
tokenized_documents = self.load_tokenized_preprocessing_documents() idf = self.load_idf_41227() doc_length = len(documents) for iteration in range(0, 9): tfidf_documents = [] for index in range(iteration, 4000): doc_tfidf = [] for term in idf.keys(): tf = self.term_frequency(term, tokenized_documents[index]) doc_tfidf.append(tf * idf[term]) doc = documents[index] tfidf = [doc_tfidf, doc[0], doc[1]] tfidf_documents.append(tfidf) print("{} from {} document {}".format(index, doc_length, doc[0])) self.save_tfidf_41227(tfidf_documents, iteration)
from https://stackoverflow.com/questions/31468117/python-3-can-pickle-handle-byte-objects-larger-than-4gb by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 목록에있는 값의 일부보다 큰 목록의 목록을 반환합니다. (0) | 2018.10.25 |
---|---|
[PYTHON] import 문 앞에 pythonpath를 설정하십시오. (0) | 2018.10.25 |
[PYTHON] 파이썬 로그로 두 번 나타나는 로그 메시지 (0) | 2018.10.25 |
[PYTHON] 키에 특정 문자열이 들어있는 파이썬 사전의 항목 필터링 (0) | 2018.10.25 |
[PYTHON] except 블록을 테스트하기 위해 예외를 발생시키는 함수 조롱 (0) | 2018.10.25 |