Почему многопроцессорная обработка.Процесс здесь не работает?

#python #multiprocessing

Вопрос:

Я тестирую многопроцессорную обработку на ноутбуке jupyter и spyder:

 import multiprocessing
import time

start = time.perf_counter()

def do_something():
    print(f'Sleeping 5 second(s)...')
    time.sleep(5)
    print(f'Done Sleeping...') 


p2 = multiprocessing.Process(target = do_something)
p3 = multiprocessing.Process(target = do_something)

p2.start()
p3.start()

p2.join()
p3.join()

finish = time.perf_counter()

print(f'Finished in {round(finish-start, 2)} secounds')
 

И я получил:

 Finished in 0.12 secounds
 

Это намного меньше, чем 5 секунд.
Я протестировал функцию do_something, и, похоже, все в порядке. Я чувствую, что в приведенном выше коде функция do_someting даже не была выполнена…

 start = time.perf_counter()

def do_something(seconds):
    print(f'Sleeping {seconds} second(s)...')
    time.sleep(seconds)
    print(f'Done Sleeping...{seconds}') 

do_something(5)

finish = time.perf_counter()

print(f'Finished in {round(finish-start, 2)} secounds')


Sleeping 5 second(s)...
Done Sleeping...5
Finished in 5.0 secounds
 

Комментарии:

1. Проблема в том, что вы запускаете свой сценарий на ноутбуке jupyter и spyder . Сохраните свой сценарий и выполните его непосредственно с помощью python, и он будет работать.

2. @Corralien, это потому, что у меня есть «печать» в функции или что-то еще?

Ответ №1:

Ваш код должен выдать ошибку (я не буду писать обратную трассировку, чтобы сократить ответ).:

 RuntimeError: 
    An attempt has been made to start a new process before the
    current process has finished its bootstrapping phase.

    This probably means that you are not using fork to start your
    child processes and you have forgotten to use the proper idiom
    in the main module:

        if __name__ == '__main__':
            freeze_support()
            ...

    The "freeze_support()" line can be omitted if the program
    is not going to be frozen to produce an executable.
 

Короче говоря, многопроцессорный пакет не может правильно понять и выполнить ваш код. Вы должны сохранить определения в начале файла и поместить код, который вы хотите выполнить, внутрь

 if __name__ == '__main__':
 

В противном случае каждый новый процесс будет пытаться выполнить один и тот же файл (а также порождать другие процессы). На моем компьютере выполнение исправленного кода занимает около 5,22 секунды.

Необходимость «если» объясняется в руководстве по программированию (раздел «Безопасный импорт основного модуля») пакета многопроцессорной обработки. Обязательно прочтите их, чтобы избежать нежелательного поведения: многопоточность и многопроцессорность подвержены неуловимым ошибкам при неправильном использовании.

Вот исправленный код:

 import multiprocessing
import time

def do_something():
    print('Sleeping 5 seconds...')
    time.sleep(5)
    print('Done Sleeping.') 

if __name__ == '__main__':
    start = time.perf_counter()

    p2 = multiprocessing.Process(target=do_something, args=())
    p3 = multiprocessing.Process(target=do_something, args=())

    p2.start()
    p3.start()

    p2.join()
    p3.join()

    finish = time.perf_counter()

    print(f'Finished in {round(finish-start, 2)} seconds')
 

Почему вы видите результат через 0,12 секунды? Это происходит потому, что каждый дочерний процесс выдает свою ошибку и завершает работу (вы должны получить две одинаковые ошибки во время выполнения), после чего родительский процесс может завершиться.

Комментарии:

1. Спасибо за объяснение. Я импортировал функцию из внешнего файла БЕЗ проверки имени , и она нормально работает в команде. Я также запустил ваш код в сценарии, и это тоже нормально.