W moim projekcie używam biblioteki Pythona multiprocessing
do tworzenia wielu procesów w __main__. Projekt jest pakowany do pojedynczego pliku EXE systemu Windows przy użyciu PyInstaller 2.1.1.Program EXE systemu Windows skompilowany przez PyInstaller kończy się niepowodzeniem z wieloprocesowym przetwarzaniem
tworzę nowe procesy tak:
from multiprocessing import Process
from Queue import Empty
def _start():
while True:
try:
command = queue.get_nowait()
# ... and some more code to actually interpret commands
except Empty:
time.sleep(0.015)
def start():
process = Process(target=_start, args=args)
process.start()
return process
I __main__:
if __name__ == '__main__':
freeze_support()
start()
Niestety, podczas pakowania aplikacji do EXE i uruchomienia go, mam WindowsError
5 lub 6 (wydaje losowo) w tej linii:
command = queue.get_nowait()
Przepis na stronie PyInstaller twierdzi, że Muszę zmodyfikować mój kod, aby włączyć obsługę wieloprocesową w systemie Windows podczas pakowania aplikacji jako pojedynczego pliku.
Jestem odtwarzając kod tutaj:
import multiprocessing.forking
import os
import sys
class _Popen(multiprocessing.forking.Popen):
def __init__(self, *args, **kw):
if hasattr(sys, 'frozen'):
# We have to set original _MEIPASS2 value from sys._MEIPASS
# to get --onefile mode working.
# Last character is stripped in C-loader. We have to add
# '/' or '\\' at the end.
os.putenv('_MEIPASS2', sys._MEIPASS + os.sep)
try:
super(_Popen, self).__init__(*args, **kw)
finally:
if hasattr(sys, 'frozen'):
# On some platforms (e.g. AIX) 'os.unsetenv()' is not
# available. In those cases we cannot delete the variable
# but only set it to the empty string. The bootloader
# can handle this case.
if hasattr(os, 'unsetenv'):
os.unsetenv('_MEIPASS2')
else:
os.putenv('_MEIPASS2', '')
class Process(multiprocessing.Process):
_Popen = _Popen
class SendeventProcess(Process):
def __init__(self, resultQueue):
self.resultQueue = resultQueue
multiprocessing.Process.__init__(self)
self.start()
def run(self):
print 'SendeventProcess'
self.resultQueue.put((1, 2))
print 'SendeventProcess'
if __name__ == '__main__':
# On Windows calling this function is necessary.
if sys.platform.startswith('win'):
multiprocessing.freeze_support()
print 'main'
resultQueue = multiprocessing.Queue()
SendeventProcess(resultQueue)
print 'main'
Moja frustracja z tego „rozwiązania” jest to, że jeden, to jest absolutnie jasne, co dokładnie jest łatanie, a dwa, że jest napisane w taki zawiłym sposobem, że niemożliwe staje się ustalenie, które części są rozwiązaniem, a które są tylko ilustracją.
Czy ktoś może podzielić się trochę uwagą na ten temat i zapewnić wgląd w to, co dokładnie należy zmienić w projekcie, który umożliwia wieloprocesorowość w plikach wykonywalnych systemu Windows utworzonych przez PyInstaller?
Czy przepis naprawia problem? – dano
Cóż, nie jest jasne (przynajmniej dla mnie), jak zastosować przepis. Wklejenie powyższego kodu w moim głównym skrypcie Pythona również nie działa, ponieważ podnosi dwa dodatkowe wyjątki niezwiązane z moimi skryptami w Pythonie. Co mi mówi, że przepis jest zasadniczo wadliwy. – nikola
Jeśli po prostu uruchomisz przepis jako samodzielny skrypt, działa on bezbłędnie? – dano