Arhn - архитектура программирования

Доктест Python зависает с использованием ProcessPoolExecutor

Этот код отлично работает под обычным CPython 3.5:

import concurrent.futures

def job(text):
    print(text)

with concurrent.futures.ProcessPoolExecutor(1) as pool:
    pool.submit(job, "hello")

Но если вы запустите его как python -m doctest myfile.py, он зависнет. Изменение submit(job на submit(print устраняет зависание, как и использование ThreadPoolExecutor вместо ProcessPoolExecutor.

Почему он зависает при запуске под doctest?


  • Любые обновления/отзывы об ответе, который я разместил? 17.04.2018

Ответы:


1

Поэтому я думаю, что проблема связана с вашим утверждением with. Когда у тебя ниже

with concurrent.futures.ProcessPoolExecutor(1) as pool:
    pool.submit(job, "hello")

Он заставляет поток выполняться и закрываться, а затем сам. Когда вы запускаете это как основной процесс, он работает и дает потоку время для выполнения задания. Но когда вы import используете его как модуль, он не дает фоновому потоку шанса, и shutdown в пуле ожидает выполнения работы и, следовательно, deadlock

Итак, обходной путь, который вы можете использовать, приведен ниже.

import concurrent.futures

def job(text):
    print(text)

pool = concurrent.futures.ProcessPoolExecutor(1)
pool.submit(job, "hello")

if __name__ == "__main__":
    pool.shutdown(True)

Это предотвратит deadlock и позволит вам запускать doctest, а также import модуль, если хотите.

12.04.2018
  • Этот ответ немного вводит в заблуждение, потому что проблема не в операторе with. Вы можете воспроизвести это поведение без оператора with, выполнив pool = ...ProcessPoolExecutor() pool.submit(...) pool.shutdown(). Проблема в блокировке импорта, как я отметил в своем ответе. 18.04.2018
  • @daphtdazz, я с тобой согласен. Я не знал, что https://docs.python.org/3/library/imp.html#imp.lock_held процитировал это в своем ответе, я просто знал, что это тупик импорта. Когда я сказал, что проблема заключается в операторе with, я имел в виду, что __exit__ оператора ProcessPoolExecutor выполнит метод shutdown и вызовет взаимоблокировку с импортом. Ваш ответ объясняет один слой ниже моего. Оба верны в своем собственном контексте. Вы объяснили, почему это не работает, а я объяснил, как заставить это работать. 18.04.2018

  • 2

    Проблема в том, что импорт модуля получает блокировку (какая блокировка зависит от вашей версии Python), см. ссылку документы для imp.lock_held.

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

    В ступенчатой ​​форме:

    1. Основной процесс получает блокировку для импорта myfile.py
    2. Основной процесс начинает импортировать myfile.py (он должен импортировать myfile.py, потому что именно здесь определена ваша функция job(), поэтому она не блокируется для print()).
    3. Основной процесс запускается и блокируется подпроцессом.
    4. Подпроцесс пытается получить блокировку для импорта myfile.py

    => Тупик.

    17.04.2018

    3

    doctest импортирует ваш модуль для его обработки. Попробуйте добавить это, чтобы предотвратить выполнение при импорте:

    if __name__ == "__main__":
        with concurrent.futures.ProcessPoolExecutor(1) as pool: 
            pool.submit(job, "hello")
    
    12.01.2018
  • Это обходит проблему, предотвращая выполнение всего кода. Но я не хочу препятствовать запуску кода, я хочу, чтобы он не зависал. 12.01.2018
  • Код должен запускаться при загрузке модуля (например, с помощью doctest или обычного импорта) или запускаться как отдельный скрипт. 12.01.2018

  • 4

    На самом деле это должен быть комментарий, но он слишком длинный.

    Ваш код не работает, если он также импортирован как модуль, с той же ошибкой, что и doctest. Я получаю _pickle.PicklingError: Can't pickle <function job at 0x7f28cb0d2378>: import of module 'a' failed (я назвал файл a.py).

    Отсутствие у вас if __name__ == "__main__": нарушает правила программирования для многопроцессорной обработки: https://docs.python.org/3.6/library/multiprocessing.html#the-spawn-and-forkserver-start-methods

    Я предполагаю, что дочерние процессы также попытаются импортировать модуль, который затем попытается запустить другой дочерний процесс (поскольку пул выполняется безоговорочно). Но я не уверен на 100% в этом. Я также не уверен, почему вы получаете ошибку can't pickle <function>.

    Проблема здесь, похоже, в том, что вы хотите, чтобы модуль автоматически запускал процесс при импорте. Я не уверен, возможно ли это.

    11.04.2018
  • Я вижу, что ты говоришь. Тем не менее, проблема в том, что я хочу иметь возможность запускать ProcessPoolExecutor в рамках doctest. Это то, что я не могу заставить себя работать. Простое сокрытие всего кода под if name == "main" не работает, потому что это предотвращает запуск кода (под doctest). 12.04.2018
  • Почему бы не поместить код ProcessPoolExecutor в строку doctest, чтобы он запускал его как тест? Или есть какой-то другой вариант использования? 12.04.2018
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..