Що означає "вбитий", коли обробка величезного CSV за допомогою Python, яка раптово зупиняється?


89

У мене є сценарій 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
Опублікуйте точне формулювання повідомлення про помилку, яке ви отримуєте.
Роберт Харві,

2
"вбито" загалом означає, що процес отримав якийсь сигнал, який змусив його вийти. У цьому випадку, оскільки це відбувається одночасно зі сценарієм, є велика ймовірність, що це непрацюючий канал, процес намагається прочитати з або записати в дескриптор файлу, який був закритий на іншому кінці.
Ендрю Кларк,

3
Це не відповідь про те, звідки killedнадходить повідомлення, але якщо це пов’язано з перевищенням якогось обмеження системної пам’яті, ви, можливо, зможете це виправити, використовуючи counter.iteritems()замість counter.items()останнього циклу. У Python 2 itemsповертає список ключів і значень у словнику, що може зажадати багато пам'яті, якщо він дуже великий. На відміну від цього, iteritemsє генератором, який вимагає лише невеликого обсягу пам'яті в будь-який момент часу.
Blckknght

Відповіді:


101

Код виходу 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 повинен розглянути можливість поступового читання та обробки файлу замість усіх відразу.
Кевін,

24

Задіяні дві області зберігання: стек і купа. У стеку зберігається поточний стан виклику методу (тобто локальні змінні та посилання), а в купі зберігаються об’єкти. рекурсія і пам'ять

Я здогадуюсь, що в counterdict є занадто багато ключів, які споживають занадто багато пам'яті області купи, тому середовище виконання 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

Список літератури

2

Я сумніваюся, що щось вбиває процес лише тому, що це займає багато часу. Вбивство загалом означає, що щось іззовні завершило процес, але, мабуть, не в цьому випадку натискання Ctrl-C, оскільки це призведе до виходу Python на виняток KeyboardInterrupt. Крім того, у Python ви отримаєте виняток MemoryError, якби це була проблема. Що може відбуватися, це те, що ви потрапляєте на помилку в Python або стандартний код бібліотеки, що спричиняє збій процесу.


Збійна помилка набагато частіше призведе до segfault, ніж отримання SIGKILL, якщо тільки Python не має raise(SIGKILL)десь у своєму коді з якихось причин.
Кевін,

1
Помилка в python не надсилає 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 обраний жертвою (завдяки використанню + 9 Гб загальної кількості вм), тому oom_killer зібрав його.

Ось стаття про поведінку OOM .


1
+1, лише для уточнення, щоб зрозуміти, скільки оперативної пам’яті намагається використовувати моя програма, чи слід мені складати значення total-vm, anon-rss, file-rss? Також і total-vm надає, скільки використовує моя програма, а не фактично доступну пам'ять, так? Вибачте, обмежені знання.
momo

1
Мої знання також обмежені в цьому контексті, @momo. У мене трохи часу на подальші розслідування, але я знайшов цю публікацію, яка може допомогти: stackoverflow.com/questions/18845857/… . Що я можу вам сказати, так це те, що дійсно total-vm - це обсяг пам'яті, який використовується процесом.
ivanleoncz

0

Щойно у мене трапилося те саме, коли я спробував запустити скрипт python із спільної папки в VirtualBoxрамках нового Ubuntu 20.04 LTS. Python виручав під Killedчас завантаження власної особистої бібліотеки. Коли я перемістив папку в локальний каталог, проблема зникла. Здається, Killedзупинка сталася під час початкового імпорту моєї бібліотеки, оскільки я отримував повідомлення про відсутні бібліотеки після того, як перемістив папку.

Проблема зникла після перезавантаження комп’ютера.

Отже, люди можуть спробувати перемістити програму в локальний каталог, якщо це надмірна частка, або це може бути тимчасовою проблемою, яка вимагає просто перезавантаження ОС.


Зачекайте, вам довелося перезавантажити ваш хост або віртуальну машину?
cglacet

Так. У моєму випадку я будував нову віртуальну машину, і я щойно встановив Python, коли побачив цю проблему. Після перезавантаження він пішов. Я ненавиджу перезавантаження як спосіб виправити речі, тому я витратив купу часу, намагаючись налагодити і після години копання, в тому числі тут, у SO. Але навіть, я здався, перезавантажився і перейшов. Я не уявляю, чому це спрацювало.
Тімоті К. Квін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.