RuntimeError у Windows, що намагається багатопроцесорну роботу пітона


123

Я пробую свою першу офіційну програму python, використовуючи Threading та Multiprocessing на машині Windows. Я не можу запустити процеси, хоча python надає наступне повідомлення. Справа в тому, що я не запускаю свої потоки в основний модуль. Нитки обробляються в окремому модулі всередині класу.

EDIT : До речі, цей код відмінно працює на ubuntu. Не зовсім на вікнах

RuntimeError: 
            Attempt to start a new process before the current process
            has finished its bootstrapping phase.
            This probably means that you are on Windows 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 a Windows executable.

Мій оригінальний код досить довгий, але мені вдалося відтворити помилку в скороченій версії коду. Він розділений на два файли, перший є основним модулем і робить зовсім мало, крім імпорту модуля, який обробляє процеси / потоки та викликає метод. Другий модуль - там, де знаходиться м'ясо коду.


testMain.py:

import parallelTestModule

extractor = parallelTestModule.ParallelExtractor()
extractor.runInParallel(numProcesses=2, numThreads=4)

paralTestModule.py:

import multiprocessing
from multiprocessing import Process
import threading

class ThreadRunner(threading.Thread):
    """ This class represents a single instance of a running thread"""
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name
    def run(self):
        print self.name,'\n'

class ProcessRunner:
    """ This class represents a single instance of a running process """
    def runp(self, pid, numThreads):
        mythreads = []
        for tid in range(numThreads):
            name = "Proc-"+str(pid)+"-Thread-"+str(tid)
            th = ThreadRunner(name)
            mythreads.append(th) 
        for i in mythreads:
            i.start()
        for i in mythreads:
            i.join()

class ParallelExtractor:    
    def runInParallel(self, numProcesses, numThreads):
        myprocs = []
        prunner = ProcessRunner()
        for pid in range(numProcesses):
            pr = Process(target=prunner.runp, args=(pid, numThreads)) 
            myprocs.append(pr) 
#        if __name__ == 'parallelTestModule':    #This didnt work
#        if __name__ == '__main__':              #This obviously doesnt work
#        multiprocessing.freeze_support()        #added after seeing error to no avail
        for i in myprocs:
            i.start()

        for i in myprocs:
            i.join()

@doctorlove Я запускаю його як python testMain.py
NG Algo

1
Звичайно - вам потрібно if name == ' main ', дивіться відповіді та документи
doctorlove

1
@NGAlgo Ваш сценарій був дуже корисним для мене, коли я налагоджував проблему з pymongo та мультипроцесором. Дякую!
Глина

Відповіді:


175

У Windows підпроцеси імпортуватимуть (тобто виконувати) головний модуль при запуску. Вам потрібно вставити if __name__ == '__main__':захист у основний модуль, щоб уникнути рекурсивного створення підпроцесів.

Змінено testMain.py:

import parallelTestModule

if __name__ == '__main__':    
    extractor = parallelTestModule.ParallelExtractor()
    extractor.runInParallel(numProcesses=2, numThreads=4)

3
(притискає долоню до чола) До! Це працює!!!! Дуже дякую! Мені не вистачало факту, що це оригінальний головний модуль, який повторно імпортується! Весь цей час я намагався перевірити " name ==" прямо перед тим, де запустив свої процеси.
NG Algo

1
Я не можу імпортувати 'паралельнийTestModule'. Я використовую Python 2.7. Чи повинен він працювати поза коробкою?
Jonny

2
@Jonny Код paralelTestModule.py є частиною питання.
Janne Karila

1
@DeshDeepSingh Фрагмент коду не є окремим прикладом; це модифікація коду ОП
Janne Karila

1
@DeshDeepSingh Цей модуль є частиною питання.
Janne Karila

25

Спробуйте ввести свій код всередині основної функції в testMain.py

import parallelTestModule

if __name__ ==  '__main__':
  extractor = parallelTestModule.ParallelExtractor()
  extractor.runInParallel(numProcesses=2, numThreads=4)

Дивіться документи :

"For an explanation of why (on Windows) the if __name__ == '__main__' 
part is necessary, see Programming guidelines."

які кажуть

"Переконайтесь, що новий модуль Python може бути безпечно імпортований за допомогою нового інтерпретатора Python, не викликаючи навмисних побічних ефектів (такий запуск нового процесу)."

... за допомогою if __name__ == '__main__'


9

Хоча попередні відповіді правильні, є невелике ускладнення, яке допоможе зауважити.

Якщо ваш основний модуль імпортує інший модуль, у якому глобальні змінні чи змінні члена класу визначені та ініціалізовані для (або використання) деяких нових об'єктів, можливо, вам доведеться умовити імпорт таким же чином:

if __name__ ==  '__main__':
  import my_module

3

Як сказав @Ofer, коли ви використовуєте інші бібліотеки чи модулі, вам слід імпортувати їх всередині if __name__ == '__main__':

Отже, у моєму випадку закінчилося так:

if __name__ == '__main__':       
    import librosa
    import os
    import pandas as pd
    run_my_program()

0

У моєму випадку це була проста помилка в коді, використовуючи змінну до її створення. Варто перевірити це, перш ніж спробувати вищевказані рішення. Чому я отримав саме це повідомлення про помилку, Господь знає.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.