#python #multiprocessing #psycopg2 #zombie-process
#python #многопроцессорность #psycopg2 #зомби-процесс
Вопрос:
Я пытаюсь вставить и обновить несколько миллионов строк, используя psycopg и многопроцессорность. Руководствуясь документацией, найденной в http://initd.org/psycopg/docs/usage.html#thread-and-process-safety , каждый дочерний элемент имеет свое собственное подключение к базе данных.
Но в ходе выполнения запускается только один дочерний элемент, в то время как остальные становятся зомби. Скрипт сам по себе довольно прост, и вот его урезанная версия,
import os
import psycopg2
from multiprocessing import Process
def _target(args):
# Each forked process will have its own connection
# http://initd.org/psycopg/docs/usage.html#thread-and-process-safety
conn = get_db_connection()
# Stuff seems to execute till this point in all the children
print os.getpid(), os.getppid()
# Do some updates here. After this only one child is active and running
# Others become Zombies after a while.
if __name__ == '__main__':
args = "Foo"
for i in xrange(3):
p = Process(target=_target, args=(args,))
p.start()
Я также проверил, есть ли в таблицах повышенная блокировка, заглянув в pg_locks
, но, похоже, это не так. Я упускаю что-то очевидное?
Комментарии:
1. Что делает get_db_connection? Это создает новое соединение или возвращает общее соединение? Согласно документам, которые вы разместили, это должно создавать новое соединение.
2. Филип, нет, он не использует общее соединение. Для каждого разветвленного дочернего элемента создается новый набор соединений и курсор. (должно было быть create_db_connection() )
Ответ №1:
ваши процессы становятся зомби, потому что задания завершены, но процессы не объединены. Я воспроизвел вашу проблему с помощью этого единственного теста (я добавил режим сна для имитации длительных заданий) :
import os
import time
from multiprocessing import Process
def _target(args):
print os.getpid(), os.getppid()
time.sleep(2)
print os.getpid(), "will stop"
if __name__ == '__main__':
args = "Foo"
for i in xrange(3):
p = Process(target=_target, args=(args,))
p.start()
import time
time.sleep(10)
при выполнении этого, после того, как 3 процесса напечатают, что они остановятся, они становятся в представлении ps (они больше не двигаются, но на самом деле не мертвы, потому что отец все еще удерживает их).
Если я заменю основную часть этим, у меня больше не будет зомби :
if __name__ == '__main__':
args = "Foo"
processes = []
for i in xrange(3):
p = Process(target=_target, args=(args,))
processes.append(p)
p.start()
for p in processes:
p.join()
import time
time.sleep(10)
Комментарии:
1. Седрик, проблема, с которой я столкнулся, заключалась в том, что запускался только один дочерний элемент, в то время как остальные становились зомби. Проблема, кстати, оказалась тупиковой в Postgres