[PYTHON] Python readlines () 읽기 및 사용법
PYTHONPython readlines () 읽기 및 사용법
폴더에서 ~ 1000KB의 텍스트 파일 (~ 400KB 크기의 각 파일에서 약 3000 줄)을 파싱하는 데 문제가 있습니다. 나는 readlines를 사용하여 그것들을 읽었고,
for filename in os.listdir (input_dir) :
if filename.endswith(".gz"):
f = gzip.open(file, 'rb')
else:
f = open(file, 'rb')
file_content = f.readlines()
f.close()
len_file = len(file_content)
while i < len_file:
line = file_content[i].split(delimiter)
... my logic ...
i += 1
이것은 내 입력 (50,100 파일)의 샘플을 위해 완벽하게 작동합니다. 전체 입력에서 5K 파일 이상을 실행했을 때 시간은 선형 증가분에 가깝지 않았습니다. 성능 분석을 계획하고 Cprofile 분석을 수행했습니다. 입력이 7K 파일에 도달했을 때 더 많은 파일이 급격하게 증가하는 데 걸리는 시간.
다음은 누적 리드 타임의 소요 시간입니다. 첫 번째 -> 354 개 파일 (입력 샘플) 및 두 번째 -> 7473 파일 (전체 입력)
ncalls tottime percall cumtime percall filename:lineno(function)
354 0.192 0.001 **0.192** 0.001 {method 'readlines' of 'file' objects}
7473 1329.380 0.178 **1329.380** 0.178 {method 'readlines' of 'file' objects}
이 때문에 입력 코드가 늘어남에 따라 코드에 걸리는 시간이 선형 적으로 조정되지 않습니다. 나는 사람들이 readlines ()가 전체 파일 내용을 메모리로 읽어들이므로 일반적으로 readline () 또는 read ()에 비해 더 많은 메모리를 소비한다고 주장하는 readlines ()에 대한 의사 노트를 읽습니다.
나는이 점에 동의하지만 가비지 수집기가 루프의 끝에서 메모리에서로드 된 내용을 자동으로 지워야하므로 즉석에서 내 메모리는 현재 처리 된 파일의 내용 만 가져야합니다. 그러나, 여기에 약간의 캐치가 있습니다. 누군가이 문제에 대해 통찰력을 줄 수 있습니까?
이것은 readlines ()의 고유 한 동작인가 파이썬 가비지 컬렉터에 대한 저의 잘못된 해석입니까? 알게되어 기뻐.
또한, 메모리와 시간 효율적인 방식으로 동일한 작업을 수행 할 수있는 몇 가지 대안을 제안하십시오. TIA.
해결법
-
==============================
1.짧은 버전은 : readlines ()를 사용하는 효율적인 방법은 그것을 사용하지 않는 것입니다. 이제까지.
짧은 버전은 : readlines ()를 사용하는 효율적인 방법은 그것을 사용하지 않는 것입니다. 이제까지.
readlines ()에 대한 문서는 전체 파일을 메모리로 읽어 들여이를 행으로 구문 분석하고 그 행에서 문자열로 가득 찬 목록을 작성한다는 것을 명시 적으로 보장합니다.
그러나 read ()에 대한 문서는 마찬가지로 전체 파일을 메모리로 읽어 들여 문자열을 작성하므로 도움이되지 않습니다.
더 많은 메모리를 사용하는 것 외에는 모든 것을 읽을 때까지 작업을 수행 할 수 없다는 것을 의미합니다. 가장 순진한 방식으로 읽기와 처리를 번갈아 수행한다면, 적어도 일부 파이프 라이닝 (OS 디스크 캐시, DMA, CPU 파이프 라인 등 덕택입니다.)에서 이점을 얻을 수 있습니다. 따라서 다음 배치가 실행되는 동안 한 배치에서 작업하게됩니다 읽는 중입니다. 그러나 컴퓨터가 전체 파일을 읽도록 강제하고 전체 파일을 구문 분석 한 다음 코드를 실행하면 읽기 당 하나의 중복 된 영역 대신 전체 파일에 대해 중복되는 영역 하나만 가져옵니다.
세 가지 방법으로이 문제를 해결할 수 있습니다.
예를 들어, 이것은 한번에 foo를 모두 읽어야합니다 :
with open('foo') as f: lines = f.readlines() for line in lines: pass
그러나 이것은 한 번에 약 8K 만 읽습니다.
with open('foo') as f: while True: lines = f.readlines(8192) if not lines: break for line in lines: pass
그리고 한 번에 한 줄만 읽습니다. 파이썬은 일을 더 빠르게하기 위해 좋은 버퍼 크기를 선택할 수 있습니다.
with open('foo') as f: while True: line = f.readline() if not line: break pass
그리고 이것은 이전과 똑같은 일을 할 것입니다 :
with open('foo') as f: for line in f: pass
그 동안에:
파이썬은 가비지 수집에 대해 그러한 보장을하지 않습니다.
CPython 구현은 GC에서 refcounting을 사용합니다. 즉, 코드에서, file_content가 리바운드되거나 사라지 자마자 거대한 문자열 목록과 그 안에있는 모든 문자열이 freelist로 해제됩니다. 즉, 동일한 메모리를 다음 번 통과시 다시 사용할 수 있습니다.
그러나 할당, 복사 및 할당 해제는 모두 무료가 아닙니다. 수행하지 않는 것이 훨씬 더 빠릅니다.
그 중에서도 동일한 작은 메모리 덩어리를 반복적으로 재사용하는 대신 문자열을 여러 메모리에 분산시켜 캐시 동작을 손상시킬 수 있습니다.
게다가, 메모리 사용량이 일정 할 수도 있지만 (파일 크기의 합계가 아닌 가장 큰 파일의 크기가 선형 임), mallocs를 처음으로 확장하는 것은 가장 느린 것 중 하나가 될 것입니다 당신이하는 일들 (성능 비교를하기가 훨씬 어려워집니다).
이 모든 것을 한 데 모으면 다음과 같이 프로그램을 작성합니다.
for filename in os.listdir(input_dir): with open(filename, 'rb') as f: if filename.endswith(".gz"): f = gzip.open(fileobj=f) words = (line.split(delimiter) for line in f) ... my logic ...
아니면, 아마도 :
for filename in os.listdir(input_dir): if filename.endswith(".gz"): f = gzip.open(filename, 'rb') else: f = open(filename, 'rb') with contextlib.closing(f): words = (line.split(delimiter) for line in f) ... my logic ...
-
==============================
2.전체 파일이 아니라 한 줄씩 읽습니다.
전체 파일이 아니라 한 줄씩 읽습니다.
for line in open(file_name, 'rb'): # process line here
자동으로 파일을 닫을 때 사용하는 것이 더 좋습니다.
with open(file_name, 'rb') as f: for line in f: # process line here
위의 예제는 한 번에 한 줄씩 반복자를 사용하여 파일 객체를 읽습니다.
from https://stackoverflow.com/questions/17246260/python-readlines-usage-and-efficient-practice-for-reading by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 파이썬의 'in'연산자를 재정의 하시겠습니까? (0) | 2018.10.07 |
---|---|
[PYTHON] Tensorflow C ++에서 그래프를 내보내고 실행하는 다양한 방법 (0) | 2018.10.07 |
[PYTHON] 중첩 된 사전의 항목에서 팬더 DataFrame 구성 (0) | 2018.10.07 |
[PYTHON] 파이썬 목록에서 중복을 제거하고 순서를 유지하는 방법? [복제] (0) | 2018.10.07 |
[PYTHON] 파이썬 모범 사례와 securest를 사용하여 MySQL에 연결하고 쿼리 실행 (0) | 2018.10.07 |