파이썬으로 거대한 CSV 처리가 갑자기 멈출 때 'killed'는 무엇을 의미합니까?


89

큰 CSV 파일을 가져온 다음 파일에서 각 단어의 발생 횟수를 계산 한 다음 다른 CSV 파일로 내보내는 Python 스크립트가 있습니다.

그러나 일어나는 일은 일단 계산 부분이 완료되고 내보내기가 시작 Killed되면 터미널에 말합니다 .

나는 이것이 메모리 문제라고 생각하지 않습니다 (만약 내가 메모리 오류가 아니라고 가정한다면 Killed).

프로세스가 너무 오래 걸릴 수 있습니까? 그렇다면 제한 시간을 연장하여 이것을 피할 수 있습니까?

다음은 코드입니다.

csv.field_size_limit(sys.maxsize)
    counter={}
    with open("/home/alex/Documents/version2/cooccur_list.csv",'rb') as file_name:
        reader=csv.reader(file_name)
        for row in reader:
            if len(row)>1:
                pair=row[0]+' '+row[1]
                if pair in counter:
                    counter[pair]+=1
                else:
                    counter[pair]=1
    print 'finished counting'
    writer = csv.writer(open('/home/alex/Documents/version2/dict.csv', 'wb'))
    for key, value in counter.items():
        writer.writerow([key, value])

그리고 인쇄 Killed후 발생 finished counting하며 전체 메시지는 다음과 같습니다.

killed (program exited with code: 137)

6
표시되는 오류 메시지의 정확한 문구를 게시하십시오.
Robert Harvey

2
"killed"는 일반적으로 프로세스가 종료를 유발하는 신호를 수신했음을 의미합니다. 이 경우 스크립트와 동시에 발생하기 때문에 깨진 파이프 일 가능성이 높으므로 프로세스는 다른 쪽 끝에서 닫힌 파일 핸들에서 읽거나 쓰려고합니다.
Andrew Clark

3
killed메시지가 어디에서 왔는지에 대한 대답은 아니지만 어떤 종류의 시스템 메모리 제한을 초과 한 경우 최종 루프 counter.iteritems()대신 사용하여 수정할 수 있습니다 counter.items(). Python 2 items에서 사전에있는 키 및 값 목록을 반환합니다. 이는 매우 큰 경우 많은 메모리가 필요할 수 있습니다. 반대로 iteritems는 주어진 시간에 소량의 메모리 만 필요로하는 생성기입니다.
Blckknght 2010 년

답변:


101

종료 코드 137 (128 + 9)은 신호 9를 수신하여 프로그램이 종료되었음을 나타냅니다 SIGKILL. 이것은 또한 killed메시지를 설명합니다 . 문제는 왜 그 신호를 받았습니까?

가장 가능성이 높은 이유는 아마도 프로세스가 사용할 수있는 시스템 리소스 양의 일부 제한을 초과했기 때문일 것입니다. OS 및 구성에 따라 열린 파일이 너무 많거나 파일 시스템 공간을 너무 많이 사용했거나 다른 것을 사용할 수 있습니다. 프로그램이 너무 많은 메모리를 사용하고있을 가능성이 가장 높습니다. 메모리 할당이 실패하기 시작했을 때 문제가 발생할 위험이있는 대신 시스템은 너무 많은 메모리를 사용하는 프로세스에 종료 신호를 보냈습니다.

앞서 언급했듯이 인쇄 후 메모리 제한에 도달 할 수있는 한 가지 이유 finished countingcounter.items()최종 루프에서에 대한 호출이 사전의 모든 키와 값을 포함하는 목록을 할당하기 때문입니다. 사전에 많은 양의 데이터가있는 경우 이는 매우 큰 목록 일 수 있습니다. 가능한 해결책은 counter.iteritems()발전기 를 사용 하는 것입니다. 목록의 모든 항목을 반환하는 대신 훨씬 적은 메모리 사용으로 항목을 반복 할 수 있습니다.

따라서 최종 루프로 이것을 시도하는 것이 좋습니다.

for key, value in counter.iteritems():
    writer.writerow([key, value])

Python 3에서는 itemsPython 2 버전과 동일한 오버 헤드가없는 "dictionary view"객체를 반환합니다. 을 대체 iteritems하므로 나중에 Python 버전을 업그레이드하면 루프를 원래대로 다시 변경하게됩니다.


2
맞지만 사전 자체도 많은 메모리를 차지합니다. OP는 한 번에 모두 파일을 읽고 처리하는 대신 점진적으로 파일을 읽고 처리하는 것을 고려해야합니다.
케빈

24

관련된 두 가지 저장 영역이 있습니다 : 스택과 힙. 스택은 메서드 호출의 현재 상태 (예 : 로컬 변수 및 참조)가 보관되는 곳이고 힙은 객체가 저장되는 곳입니다. 재귀와 기억

counter힙 영역의 메모리를 너무 많이 소비 하는 딕셔너리 에 너무 많은 키가 있다고 생각하므로 Python 런타임은 OutOfMemory 예외를 발생시킵니다.

저장하려면 카운터 와 같은 거대한 물체를 만들지 마십시오. .

1. 스택 오버플로

너무 많은 지역 변수를 생성하는 프로그램.

Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('stack_overflow.py','w')
>>> f.write('def foo():\n')
>>> for x in xrange(10000000):
...   f.write('\tx%d = %d\n' % (x, x))
... 
>>> f.write('foo()')
>>> f.close()
>>> execfile('stack_overflow.py')
Killed

2.OutOfMemory

거인을 만드는 프로그램 dict에는 너무 많은 키가 포함되어 있습니다.

>>> f = open('out_of_memory.py','w')
>>> f.write('def foo():\n')
>>> f.write('\tcounter = {}\n')
>>> for x in xrange(10000000):
...   f.write('counter[%d] = %d\n' % (x, x))
... 
>>> f.write('foo()\n')
>>> f.close()
>>> execfile('out_of_memory.py')
Killed

참고 문헌

2

시간이 오래 걸린다는 이유만으로 프로세스를 죽이는 것은 의심 스럽습니다. Killed는 일반적으로 외부에서 프로세스가 종료되었음을 의미하지만이 경우 Ctrl-C를 누르면 Python이 KeyboardInterrupt 예외로 종료되기 때문에이 경우는 아닐 것입니다. 또한 Python에서 문제가 발생하면 MemoryError 예외가 발생합니다. 일어날 수있는 일은 Python 또는 표준 라이브러리 코드에서 버그가 발생하여 프로세스 충돌을 유발하는 것입니다.


SIGKILL파이썬이 raise(SIGKILL)어떤 이유로 코드에 어딘가에 있지 않는 한 충돌 버그는 얻는 것보다 segfault를 초래할 가능성이 훨씬 더 높습니다 .
케빈

1
파이썬의 버그는 SIGKILL을 보내지 않습니다.
qwr

2

아마도 메모리가 부족하여 커널이 프로세스를 종료했습니다.

OOM Killer 에 대해 들어 보셨습니까 ?

다음은 CSV 파일의 방대한 데이터 집합을 처리하기 위해 개발 한 스크립트의 로그입니다.

Mar 12 18:20:38 server.com kernel: [63802.396693] Out of memory: Kill process 12216 (python3) score 915 or sacrifice child
Mar 12 18:20:38 server.com kernel: [63802.402542] Killed process 12216 (python3) total-vm:9695784kB, anon-rss:7623168kB, file-rss:4kB, shmem-rss:0kB
Mar 12 18:20:38 server.com kernel: [63803.002121] oom_reaper: reaped process 12216 (python3), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

에서 가져 왔습니다 /var/log/syslog.

원래:

PID 12216이 피해자 로 선출 되었으므로 (총 VM의 + 9Gb 사용으로 인해) oom_killer가이를 거두었습니다.

다음은 OOM 동작 에 대한 기사 입니다.


1
+1, 내 프로그램이 사용하려는 RAM의 양을 이해하기 위해 total-vm, anon-rss, file-rss 값을 더해야합니까? 또한 total-vm은 내 프로그램이 실제 사용 가능한 메모리가 아닌 사용중인 양을 제공합니다. 미안하지만 제한된 지식입니다.
momo

1
내 지식은이 컨텍스트 @momo에 대해서도 제한되어 있습니다. 추가 조사를 위해 시간이 좀 부족하지만 도움이 될만한 게시물을 찾았습니다. stackoverflow.com/questions/18845857/… . 제가 말할 수있는 것은 실제로 total-vm은 프로세스에서 사용하는 메모리 양이라는 것입니다.
ivanleoncz

0

VirtualBox새로운 Ubuntu 20.04 LTS 의 공유 폴더에서 Python 스크립트를 실행하려고 할 때도 똑같은 일이 발생했습니다 . Killed내 개인 라이브러리를로드 하는 동안 Python이 구제되었습니다 . 폴더를 로컬 디렉토리로 옮겼을 때 문제가 사라졌습니다. 그것은 나타납니다Killed폴더를 이동 한 후 누락 된 라이브러리 메시지를 받았기 때문에 라이브러리의 초기 가져 오기 중에 중지 된 .

컴퓨터를 다시 시작한 후 문제가 사라졌습니다.

따라서 사람들은 어떤 종류의 공유를 통해 프로그램을 로컬 디렉토리로 옮기거나 OS를 재부팅해야하는 일시적인 문제 일 수 있습니다.


잠깐, 호스트 또는 VM을 재부팅해야 했습니까?
cglacet

예. 제 경우에는 새 VM을 구축하고 있었는데이 문제를 보았을 때 방금 Python을 설치했습니다. 재부팅 후 사라졌습니다. 나는 문제를 해결하는 방법으로 재부팅하는 것이 싫기 때문에 디버깅을 시도하고 여기 SO를 포함하여 한 시간 동안 파고 들었습니다. 그러나 결국 나는 포기하고 재부팅하고 presto. 왜 효과가 있었는지 모르겠습니다.
Timothy C. Quinn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.