Как мне обработать события KeyboardInterrupt с помощью многопроцессорных пулов Python? Вот простой пример:
from multiprocessing import Pool
from time import sleep
from sys import exit
def slowly_square(i):
sleep(1)
return i*i
def go():
pool = Pool(8)
try:
results = pool.map(slowly_square, range(40))
except KeyboardInterrupt:
# **** THIS PART NEVER EXECUTES. ****
pool.terminate()
print "You cancelled the program!"
sys.exit(1)
print "\nFinally, here are the results: ", results
if __name__ == "__main__":
go()
При запуске кода выше, KeyboardInterrupt
когда я нажимаю ^C
, возникает ошибка , но в этот момент процесс просто зависает, и мне приходится убивать его извне.
Я хочу быть в состоянии нажать ^C
в любое время и заставить все процессы завершиться изящно.
python
multiprocessing
pool
keyboardinterrupt
Fragsworth
источник
источник
Ответы:
Это ошибка Python. При ожидании условия в threading.Condition.wait () KeyboardInterrupt никогда не отправляется. Репро:
Исключение KeyboardInterrupt не будет доставлено до тех пор, пока wait () не вернется, и никогда не вернется, поэтому прерывание никогда не происходит. KeyboardInterrupt почти наверняка должен прервать ожидание условия.
Обратите внимание, что это не происходит, если указан тайм-аут; cond.wait (1) немедленно получит прерывание. Таким образом, обходной путь должен указать время ожидания. Для этого замените
с участием
или похожие.
источник
Из того, что я недавно обнаружил, лучшее решение - настроить рабочие процессы на полное игнорирование SIGINT и ограничить весь код очистки родительским процессом. Это устраняет проблему как для незанятых, так и для занятых рабочих процессов и не требует кода обработки ошибок в ваших дочерних процессах.
Объяснение и полный пример кода можно найти по адресу http://noswap.com/blog/python-multiprocessing-keyboardinterrupt/ и http://github.com/jreese/multiprocessing-keyboardinterrupt соответственно.
источник
time.sleep(10)
основным процессом. Если вы должны были удалить этот спящий режим или подождать, пока процесс не попытается присоединиться к пулу, что необходимо сделать, чтобы гарантировать, что задания завершены, то вы все равно будете страдать от той же проблемы, что и основной процесс. не получил KeyboardInterrupt во время ожиданияjoin
операции опроса .pool.terminate()
никогда не исполняется. Если дети игнорируют сигнал, это ничего не значит. Ответ @ Гленна решает проблему..join()
кроме как по прерыванию - он просто вручную проверяет результат.apply_async()
использования,AsyncResult.ready()
чтобы увидеть, готов ли он, что означает, что мы чисто закончили.По некоторым причинам, только исключения, унаследованные от базового
Exception
класса, обрабатываются нормально. В качестве обходного пути вы можете повторно поднять свойKeyboardInterrupt
в качествеException
примера:Обычно вы получите следующий вывод:
Так что если вы нажмете
^C
, вы получите:источник
KeyboardInterrupt
прибывает, когдаmultiprocessing
выполняет собственный обмен данными IPC, тогдаtry..catch
активация не будет (очевидно).raise KeyboardInterruptError
наreturn
. Вам просто нужно убедиться, что дочерний процесс завершается сразу после получения KeyboardInterrupt. Возвращаемое значение, кажется, игнорируется, в тоmain
же время получено KeyboardInterrupt.Обычно это простая структура работает Ctrl- Cна бассейн:
Как было сказано в нескольких похожих постах:
Захватить прерывание клавиатуры в Python без try-кроме
источник
Голосованный ответ не решает основную проблему, но похожий побочный эффект.
Джесси Ноллер, автор многопроцессорной библиотеки, объясняет, как правильно обращаться с CTRL + C при использовании
multiprocessing.Pool
в старом сообщении в блоге .источник
os.setpgrp()
изнутри будущегоProcessPoolExecutor
что не поддерживает функции инициализатора. В Unix вы можете использовать этуfork
стратегию, отключив sighandler в главном процессе перед созданием пула, а затем снова включив его. В pebbleSIGINT
по умолчанию я отключаю дочерние процессы. Я не знаю причину, по которой они не делают то же самое с Python Pools. В конце пользователь может переустановитьSIGINT
обработчик в случае, если он / она хочет навредить себе.Кажется, есть две проблемы, которые делают исключения при раздражающей многопроцессорности. Первый (отмеченный Гленном) заключается в том, что вам нужно использовать
map_async
тайм-аут вместоmap
того, чтобы получить немедленный ответ (т. Е. Не завершать обработку всего списка). Второй (отмеченный Андреем) заключается в том, что многопроцессорная обработка не захватывает исключения, которые не наследуются отException
(например,SystemExit
). Итак, вот мое решение, которое касается обоих из них:источник
function
это довольно долгое время (сотни секунд).map
и все хорошо.@Linux Cli Aik
ниже приведено решение, которое вызывает такое поведение. Использованиеmap_async
не всегда желательно, если основной поток зависит от результатов дочерних процессов.Я обнаружил, что на данный момент лучшее решение - не использовать функцию multiprocessing.pool, а использовать собственную функцию пула. Я представил пример, демонстрирующий ошибку с apply_async, а также пример, показывающий, как вообще не использовать функциональность пула.
http://www.bryceboe.com/2010/08/26/python-multiprocessing-and-keyboardinterrupt/
источник
Я новичок в Python. Я искал ответ везде и наткнулся на этот и несколько других блогов и видео на YouTube. Я попытался скопировать вставить код автора выше и воспроизвести его на моем Python 2.7.13 в Windows 7 64-битной. Это близко к тому, чего я хочу достичь.
Я заставил свои дочерние процессы игнорировать ControlC и заставить родительский процесс завершаться. Похоже, что обход дочернего процесса помогает избежать этой проблемы для меня.
Часть, начинающаяся с
pool.terminate()
никогда, кажется, не выполняется.источник
map_async
пользователя, что мне не особенно нравится. Во многих ситуациях, как у меня, основной поток должен ждать завершения отдельных процессов. Это одна из причин, почемуmap
существует!Вы можете попробовать использовать метод apply_async объекта Pool, например так:
Вывод:
Преимущество этого метода в том, что результаты, обработанные до прерывания, будут возвращены в словарь результатов:
источник
Как ни странно, похоже, что вы должны обращаться
KeyboardInterrupt
с детьми. Я бы ожидал, что это будет работать как написано ... попробуйте изменитьslowly_square
на:Это должно работать, как вы ожидали.
источник