'ฆ่า' หมายความว่าอย่างไรเมื่อประมวลผล CSV ขนาดใหญ่ด้วย Python ซึ่งหยุดกะทันหัน


94

ฉันมีสคริปต์ Python ที่นำเข้าไฟล์ CSV ขนาดใหญ่จากนั้นนับจำนวนครั้งที่เกิดขึ้นของแต่ละคำในไฟล์จากนั้นส่งออกการนับไปยังไฟล์ CSV อื่น

แต่สิ่งที่เกิดขึ้นคือเมื่อการนับส่วนนั้นเสร็จสิ้นและการส่งออกเริ่มขึ้นมันจะบอกว่า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
"ถูกฆ่า" โดยทั่วไปหมายความว่ากระบวนการได้รับสัญญาณบางอย่างที่ทำให้ออกจากระบบ ในกรณีนี้เนื่องจากเกิดขึ้นในเวลาเดียวกันของสคริปต์จึงมีโอกาสที่จะเป็นไปป์เสียกระบวนการจึงพยายามอ่านหรือเขียนไปยังที่จับไฟล์ที่ถูกปิดในอีกด้านหนึ่ง
Andrew Clark

3
ไม่ใช่คำตอบเกี่ยวกับที่killedมาของข้อความ แต่หากเกิดจากการเกินขีด จำกัด หน่วยความจำระบบบางประเภทคุณอาจสามารถแก้ไขได้โดยใช้counter.iteritems()แทนcounter.items()ในลูปสุดท้ายของคุณ ใน Python 2 itemsจะส่งคืนรายการคีย์และค่าในพจนานุกรมซึ่งอาจต้องใช้หน่วยความจำจำนวนมากหากมีขนาดใหญ่มาก ในทางตรงกันข้ามiteritemsเป็นเครื่องกำเนิดไฟฟ้าที่ต้องการหน่วยความจำเพียงเล็กน้อยในช่วงเวลาใดเวลาหนึ่ง
Blckknght

คำตอบ:


104

รหัส Exit 137 (128 + 9) ระบุว่าโปรแกรมของคุณออกเนื่องจากการรับสัญญาณที่ 9 SIGKILLซึ่งเป็น นอกจากนี้ยังอธิบายถึงไฟล์killedข้อความ คำถามคือทำไมคุณถึงได้รับสัญญาณนั้น?

สาเหตุที่เป็นไปได้มากที่สุดน่าจะเป็นเพราะกระบวนการของคุณเกินขีด จำกัด จำนวนทรัพยากรระบบที่คุณได้รับอนุญาตให้ใช้ ทั้งนี้ขึ้นอยู่กับระบบปฏิบัติการและการกำหนดค่าของคุณอาจหมายความว่าคุณมีไฟล์ที่เปิดอยู่มากเกินไปใช้พื้นที่ไฟล์มากเกินไปหรืออย่างอื่น เป็นไปได้มากว่าโปรแกรมของคุณใช้หน่วยความจำมากเกินไป แทนที่จะเสี่ยงกับสิ่งที่ทำลายเมื่อการจัดสรรหน่วยความจำเริ่มล้มเหลวระบบจะส่งสัญญาณฆ่าไปยังกระบวนการที่ใช้หน่วยความจำมากเกินไป

ตามที่ฉันแสดงความคิดเห็นไว้ก่อนหน้านี้เหตุผลหนึ่งที่คุณอาจถึงขีด จำกัด หน่วยความจำหลังจากพิมพ์finished countingคือการที่คุณโทรไปcounter.items()ในลูปสุดท้ายจะจัดสรรรายการที่มีคีย์และค่าทั้งหมดจากพจนานุกรมของคุณ หากพจนานุกรมของคุณมีข้อมูลจำนวนมากนี่อาจเป็นรายการที่ใหญ่มาก ทางออกที่เป็นไปได้คือการใช้counter.iteritems()ซึ่งเป็นเครื่องกำเนิดไฟฟ้า แทนที่จะส่งคืนรายการทั้งหมดในรายการช่วยให้คุณทำซ้ำได้โดยใช้หน่วยความจำน้อยลงมาก

ดังนั้นฉันขอแนะนำให้ลองสิ่งนี้เป็นลูปสุดท้ายของคุณ:

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

โปรดทราบว่าใน Python 3 itemsจะส่งคืนอ็อบเจ็กต์ "มุมมองพจนานุกรม" ซึ่งไม่มีโอเวอร์เฮดเหมือนกับเวอร์ชันของ Python 2 มันเข้ามาแทนที่iteritemsดังนั้นหากคุณอัปเกรดเวอร์ชัน Python ในภายหลังคุณจะต้องเปลี่ยนลูปกลับไปเป็นแบบเดิม


2
ถูกต้อง แต่พจนานุกรมเองก็ใช้หน่วยความจำมากเช่นกัน OP ควรพิจารณาอ่านและประมวลผลไฟล์ทีละน้อยแทนที่จะอ่านทั้งหมดพร้อมกัน
Kevin

24

มีพื้นที่จัดเก็บสองส่วนที่เกี่ยวข้อง: สแต็กและฮีปสแต็กเป็นที่เก็บสถานะปัจจุบันของการเรียกใช้เมธอด (เช่นตัวแปรโลคัลและการอ้างอิง) และฮีปคือที่เก็บอ็อบเจ็กต์ การเรียกซ้ำและหน่วยความจำ

ฉันเดาว่ามีคีย์มากเกินไปในคำสั่งcounterที่จะใช้หน่วยความจำของพื้นที่ฮีปมากเกินไปดังนั้นรันไทม์ของ Python จะเพิ่มข้อยกเว้นOutOfMemory

ในการบันทึกได้ไม่สร้างวัตถุยักษ์เช่นเคาน์เตอร์

1.StackOverflow

โปรแกรมที่สร้างตัวแปรภายในมากเกินไป

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

อ้างอิง

4

เป็นไปได้มากว่าคุณมีหน่วยความจำไม่เพียงพอดังนั้นเคอร์เนลจึงฆ่ากระบวนการของคุณ

คุณเคยได้ยินเกี่ยวกับ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 ได้รับเลือกให้เป็นเหยื่อ (เนื่องจากใช้ + 9Gb ของ total-vm) ดังนั้นoom_killerจึงเก็บเกี่ยวมัน

ต่อไปนี้เป็นบทความเกี่ยวกับพฤติกรรม OOM


1
+1 เพื่อให้เข้าใจว่าโปรแกรมของฉันพยายามใช้ RAM มากแค่ไหนฉันควรเพิ่มค่า total-vm, anon-rss, file-rss หรือไม่ นอกจากนี้และ total-vm จะให้จำนวนโปรแกรมของฉันที่ใช้และไม่ใช่หน่วยความจำที่มีอยู่จริงใช่ไหม ขออภัยความรู้ที่ จำกัด
momo

1
ความรู้ของฉันมี จำกัด เช่นกันในบริบทนี้ @momo ฉันไม่มีเวลาสำหรับการตรวจสอบเพิ่มเติม แต่ฉันพบว่าโพสต์นี้อาจช่วยได้: stackoverflow.com/questions/18845857/… . สิ่งที่ฉันบอกคุณได้คือจริงๆแล้ว total-vm คือจำนวนหน่วยความจำที่ใช้โดยกระบวนการ
ivanleoncz

3

ฉันสงสัยว่ามีอะไรฆ่ากระบวนการเพียงเพราะใช้เวลานาน ฆ่าโดยทั่วไปหมายถึงบางสิ่งจากภายนอกที่ยุติกระบวนการ แต่อาจไม่ใช่ในกรณีนี้การกด Ctrl-C เนื่องจากจะทำให้ Python ออกจากข้อยกเว้น KeyboardInterrupt นอกจากนี้ใน Python คุณจะได้รับข้อยกเว้น MemoryError หากเป็นปัญหา สิ่งที่อาจเกิดขึ้นคือคุณพบจุดบกพร่องใน Python หรือรหัสไลบรารีมาตรฐานที่ทำให้กระบวนการขัดข้อง


ข้อผิดพลาดที่ขัดข้องมีแนวโน้มที่จะส่งผลให้เกิด segfault มากกว่าการได้รับSIGKILLเว้นแต่ Python จะมีraise(SIGKILL)โค้ดอยู่ที่ไหนสักแห่งด้วยเหตุผลบางประการ
Kevin

1
ข้อผิดพลาดใน python จะไม่ส่ง SIGKILL
qwr

1

ฉันเพิ่งเกิดเหตุการณ์แบบเดียวกันกับฉันเมื่อฉันพยายามเรียกใช้สคริปต์ python จากโฟลเดอร์ที่แชร์ในVirtualBoxUbuntu 20.04 LTS ใหม่ Python ประกันตัวKilledขณะโหลดห้องสมุดส่วนตัวของฉันเอง เมื่อฉันย้ายโฟลเดอร์ไปยังไดเร็กทอรีภายในปัญหาก็หายไป ปรากฏว่าKilledหยุดจะเกิดขึ้นในระหว่างการนำเข้าห้องสมุดครั้งแรกเนื่องจากฉันได้รับข้อความของไลบรารีที่หายไปเมื่อฉันย้ายโฟลเดอร์ไป

ปัญหานี้หายไปหลังจากที่ฉันรีสตาร์ทคอมพิวเตอร์

ดังนั้นผู้คนอาจต้องการลองย้ายโปรแกรมไปยังไดเร็กทอรีภายในหากใช้งานร่วมกับบางประเภทหรืออาจเป็นปัญหาชั่วคราวที่ต้องรีบูตระบบปฏิบัติการ


เดี๋ยวก่อนคุณต้องรีบูตโฮสต์หรือ VM หรือไม่?
cglacet

1
ใช่. ในกรณีของฉันฉันกำลังสร้าง VM ใหม่และฉันเพิ่งติดตั้ง Python เมื่อฉันเห็นปัญหานี้ หลังจากรีบูตเครื่องก็หายไป ฉันเกลียดการรีบูตเป็นวิธีแก้ไขสิ่งต่าง ๆ ดังนั้นฉันจึงใช้เวลามากมายในการพยายามแก้ไขข้อบกพร่องและหลังจากขุดไปหนึ่งชั่วโมงรวมถึงที่นี่ใน SO แต่ในที่สุดฉันก็ยอมแพ้และรีบูตและ presto ฉันไม่รู้ว่าทำไมมันถึงได้ผล
Timothy C. Quinn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.