RuntimeError no Windows tentando multiprocessamento python

123

Estou tentando meu primeiro programa python formal usando Threading e Multiprocessamento em uma máquina Windows. Não consigo iniciar os processos, porém, com python apresentando a seguinte mensagem. O fato é que não estou lançando meus threads no módulo principal . Os threads são tratados em um módulo separado dentro de uma classe.

EDIT : A propósito, este código funciona bem no Ubuntu. Não é bem no windows

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.

Meu código original é bem longo, mas consegui reproduzir o erro em uma versão resumida do código. Ele é dividido em dois arquivos, o primeiro é o módulo principal e faz muito pouco além de importar o módulo que lida com processos / threads e chama um método. O segundo módulo é onde está a carne do código.


testMain.py:

import parallelTestModule

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

parallelTestModule.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()
NG Algo
fonte
@doctorlove Eu o executo como python testMain.py
NG Algo
1
Claro - você precisa de um if name == ' main ', veja as respostas e os documentos
doctorlove
1
@NGAlgo Seu script foi muito útil para mim enquanto eu estava depurando um problema com pymongo e multiprocessamento. Obrigado!
Clay

Respostas:

175

No Windows, os subprocessos irão importar (ou seja, executar) o módulo principal no início. Você precisa inserir uma if __name__ == '__main__':proteção no módulo principal para evitar a criação de subprocessos recursivamente.

Modificado testMain.py:

import parallelTestModule

if __name__ == '__main__':    
    extractor = parallelTestModule.ParallelExtractor()
    extractor.runInParallel(numProcesses=2, numThreads=4)
Janne Karila
fonte
3
(bate a palma da mão na testa) Doh! Funciona!!!! Muito obrigado! Eu estava perdendo o fato de que é o módulo principal original que é importado novamente! Todo esse tempo eu estava tentando a verificação " name ==" logo antes de inicializar meus processos.
NG Algo
1
Não consigo importar 'parallelTestModule'. Estou usando o Python 2.7. Deve funcionar fora da caixa?
Jonny
2
@Jonny O código para parallelTestModule.py é parte da questão.
Janne Karila
1
@DeshDeepSingh O fragmento de código não é um exemplo independente; é uma modificação do código do OP
Janne Karila
1
@DeshDeepSingh Esse módulo é parte da questão.
Janne Karila
25

Tente colocar seu código dentro de uma função principal em testMain.py

import parallelTestModule

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

Veja a documentação :

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

que dizem

"Certifique-se de que o módulo principal pode ser importado com segurança por um novo interpretador Python sem causar efeitos colaterais indesejados (como iniciar um novo processo)."

... usando if __name__ == '__main__'

doctorlove
fonte
9

Embora as respostas anteriores estejam corretas, há uma pequena complicação que ajudaria a comentar.

No caso de seu módulo principal importar outro módulo no qual variáveis ​​globais ou variáveis ​​de membro de classe são definidas e inicializadas para (ou usando) alguns novos objetos, você pode ter que condicionar essa importação da mesma maneira:

if __name__ ==  '__main__':
  import my_module
Ofer
fonte
3

Como @Ofer disse, quando você estiver usando outras bibliotecas ou módulos, você deve importar todos eles dentro do if __name__ == '__main__':

Então, no meu caso, acabou assim:

if __name__ == '__main__':       
    import librosa
    import os
    import pandas as pd
    run_my_program()
Luis abdi
fonte
0

No meu caso foi um bug simples no código, usando uma variável antes de ser criada. Vale a pena verificar isso antes de tentar as soluções acima. Por que recebi essa mensagem de erro específica, o Senhor sabe.

arame3333
fonte