multiprocessing.Pool порождает новый childern после terminate () на Linux/Python2.7?

У меня есть исполняемый файл, который мне нужно запускать очень часто, с разными параметрами. Для этого я написал небольшую оболочку Python (2.7), используя модуль многопроцессорности, следуя шаблону здесь .

Мой код выглядит так:

try:
     logging.info("starting pool runs")
     pool.map(run_nlin, params)
     pool.close()
 except KeyboardInterrupt:
     logging.info("^C pressed")
     pool.terminate()
 except Exception, e:
     logging.info("exception caught: ", e)
     pool.terminate()
 finally:
     time.sleep(5)
     pool.join()
     logging.info("done")

Моя рабочая функция находится здесь:

class KeyboardInterruptError(Exception): pass

def run_nlin((path_config, path_log, path_nlin, update_method)):
    try:
        with open(path_log, "w") as log_:
            cmdline = [path_nlin, path_config]
            if update_method:
                cmdline += [update_method, ]
            sp.call(cmdline, stdout=log_, stderr=log_)
    except KeyboardInterrupt:
        time.sleep(5)
        raise KeyboardInterruptError()
    except:
        raise

path_config is the path to a configuration file for the binary program; in there is e.g. the date to run the program for.

Когда я начинаю обертку, все выглядит отлично. Однако, когда я нажимаю ^ C , сценарий оболочки запускает дополнительные процессы numproc из пула перед завершением. В качестве примера, когда я запускаю скрипт для дней 1-10, я могу видеть в выводе ps aux , что два экземпляра бинарной программы работают (обычно для дней 1 и 3). Теперь, когда я нажимаю ^ C , завершается сценарий оболочки, двоичные программы для дней 1 и 3 исчезли, но есть новые двоичные программы, запущенные для дней 5 и 7.

Поэтому мне кажется, что Pool запускает еще один процесс numproc до окончательного умирания.

Любые идеи, что здесь происходит, и что я могу с этим поделать?

3
nl ja de
Используете ли вы окна или unix-подобную систему?
добавлено автор Bakuriu, источник
Linux, Py2.7. Изменено название и теги, чтобы отразить это
добавлено автор andreas-h, источник

1 ответы

На странице этой страницы Джесси Ноллер, автор модуля многопроцессорности, показывает что правильный способ обработки KeyboardInterrupt должен возвращать подпроцессы - не ререйзить исключение. Это позволяет основному процессу завершить пул.

Однако, как показывает приведенный ниже код, основной процесс не достигает блока except KeyboardInterrupt до после , все задачи, сгенерированные pool.map , имеют был запущен. Вот почему (я считаю) вы видите дополнительные вызовы вашей рабочей функции, run_nlin , после нажатия Ctrl-C .

Одним из возможных способов решения проблемы является проверка всех рабочих функций, если установлен multiprocessing.Event . Если мероприятие было установлено, попросите работника выпустить его раньше, иначе продолжите вычисление.


import logging
import multiprocessing as mp
import time

logger = mp.log_to_stderr(logging.WARNING)

def worker(x):
    try:
        if not terminating.is_set():
            logger.warn("Running worker({x!r})".format(x = x))
            time.sleep(3)
        else:
            logger.warn("got the message... we're terminating!")
    except KeyboardInterrupt:
        logger.warn("terminating is set")        
        terminating.set()
    return x

def initializer(terminating_):
    # This places terminating in the global namespace of the worker subprocesses.
    # This allows the worker function to access `terminating` even though it is
    # not passed as an argument to the function.
    global terminating
    terminating = terminating_

def main():
    terminating = mp.Event()    
    result = []
    pool = mp.Pool(initializer=initializer, initargs=(terminating, ))
    params = range(12)
    try:
         logger.warn("starting pool runs")
         result = pool.map(worker, params)
         pool.close()
    except KeyboardInterrupt:
        logger.warn("^C pressed")
        pool.terminate()
    finally:
        pool.join()
        logger.warn('done: {r}'.format(r = result))

if __name__ == '__main__':
    main()

Запуск сценария дает:

% test.py
[WARNING/MainProcess] starting pool runs
[WARNING/PoolWorker-1] Running worker(0)
[WARNING/PoolWorker-2] Running worker(1)
[WARNING/PoolWorker-3] Running worker(2)
[WARNING/PoolWorker-4] Running worker(3)

Здесь нажимается Ctrl-C; каждый из рабочих устанавливает событие terminating . Нам действительно нужно только установить его, но это работает, несмотря на небольшую неэффективность.

  C-c C-c[WARNING/PoolWorker-4] terminating is set
[WARNING/PoolWorker-2] terminating is set
[WARNING/PoolWorker-3] terminating is set
[WARNING/PoolWorker-1] terminating is set

Теперь выполняются все остальные задачи, поставленные в очередь с помощью pool.map :

[WARNING/PoolWorker-4] got the message... we're terminating!
[WARNING/PoolWorker-2] got the message... we're terminating!
[WARNING/PoolWorker-1] got the message... we're terminating!
[WARNING/PoolWorker-2] got the message... we're terminating!
[WARNING/PoolWorker-4] got the message... we're terminating!
[WARNING/PoolWorker-2] got the message... we're terminating!
[WARNING/PoolWorker-1] got the message... we're terminating!
[WARNING/PoolWorker-3] got the message... we're terminating!

Наконец, основной процесс достигает блока except KeyboardInterrupt .

[WARNING/MainProcess] ^C pressed
[WARNING/MainProcess] done: []
12
добавлено
@unutbu: очень приятное решение, время для пересмотра моего собственного кода. +1
добавлено автор isedev, источник
благодаря! сделал работу :)
добавлено автор andreas-h, источник
Python
Python
7 654 участник(ов)

Уютный чат для профессионалов, занимающихся поиском питоньих мудростей. Как не получить бан: https://t.me/ru_python/577926

Python beginners
Python beginners
4 449 участник(ов)

Вопросы про Python для чайников. Cпам и троллинг неприемлем. Не злоупотребляйте стикерами. Частозадаваемые вопросы: https://github.com/ru-python-beginners/faq/blob/master/README.md Статистика тут: https://grstats.me/chat/x4qym2k5uvfkr3al6at7

Linux Help
Linux Help
2 686 участник(ов)

Правила: https://telegra.ph/Pravila-Linux-Help-10-15

pro.python
pro.python
1 090 участник(ов)

Сообщество разработчиков под Python Создатель: @rodgelius

Rude Python
Rude Python
971 участник(ов)

Python без „девочек”, здесь матерятся и унижают Django. Not gay friendly. Правила: t.me/rudepython/114107 @rudepython | t.me/rudepython

Linux Security
Linux Security
652 участник(ов)

Данная группа принципиально про безопасность и в частности про безопасность Linux. Прочие темы просим обсуждать в профильных чатах.

rupython
rupython
509 участник(ов)

Группа создана с целью оперативного получения ответов на возникающие вопросы по разработке на яп python, смежные темы, а также человеческого общения. Приветствую!

Python-programming
Python-programming
266 участник(ов)

Чат группы вконтакте https://vk.com/python_community

Linux Gaming RUS
Linux Gaming RUS
28 участник(ов)

Русскоязычный чатик, посвящённый играм на различных дистрибутивах Linux, а также wine, proton Arch Linux RU @ArchLinuxChatRU Gnome RU @gnome_ru