3

Ich verwende Python multiprocessing.Pool Bibliothek mehrere Prozesse in der folgenden Art und Weise zu erstellen:PyInstaller eingebaute Windows-EXE nicht mit multiprocessing.pool

def parallel_function(f): 
    def easy_parallize(f, sequence): 
     """ assumes f takes sequence as input, easy w/ Python's scope """ 
     pool = Pool(processes=8) # depends on available cores 
     result = pool.map(f, sequence) # for i in sequence: result[i] = f(i) 
     cleaned = [x for x in result if x is not None] # getting results 
     cleaned = np.asarray(cleaned) 
     pool.close() 
     pool.join() 
     return cleaned 
    return partial(easy_parallize, f) 

wobei f die Funktion ist, die Arbeit und die Reihenfolge zu tun sind die Parameter, siehe http://zqdevres.qiniucdn.com/data/20150702120338/index.html für das Tutorial.

Das Projekt wird mit PyInstaller 3.1.1 in eine einzelne Windows EXE gepackt. mit der Option --onedir. PyInstaller erstellt die EXE ohne Probleme, und ich bin in der Lage, die Teile des Programms, die kein Multithreading verwenden, ohne Probleme auszuführen.

Mein Problem tritt auf, wenn ich versuche, die Teile des Programms, die die oben beschriebene Multiprocessing-Funktion verwenden, auszuführen. Dann schlägt das Programm mit der folgenden Fehlermeldung (geschrieben über und über die von jedem Kind Gewinde):

File "multiprocessing\context.py", line 148, in freeze_support 
    File "multiprocessing\spawn.py", line 74, in freeze_support 
    File "multiprocessing\spawn.py", line 106, in spawn_main 
    File "multiprocessing\spawn.py", line 115, in _main 
    File "multiprocessing\spawn.py", line 221, in prepare 
    File "multiprocessing\context.py", line 231, in set_start_method 
RuntimeError: context has already been set 
classifier_v3_gui returned -1 

Die freeze_support kommt als Vorschlag von https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing, wo der Haupt den Anruf als erste Zeile enthalten soll:

if name == "__main__": 
    multiprocessing.freeze_support() 

ein ähnliches Problem hat in PyInstaller-built Windows EXE fails with multiprocessing und bezieht sich auf die Lösung in dem obigen Link jedoch a) die diskutierte Lösung für --onedir für mich nicht diskutiert zu funktionieren scheint, wie Sie aus dem Fehler sehen Nachricht Ich bekomme, b) Ich weiß nicht, wie _Popen mit Pool-ing verwandt ist, also für --onefile, ich weiß nicht einmal wie um die Klassenredefinition zu implementieren.

Wenn ich multiprocessing.freeze_support() in main nicht benutze, verhält sich das Programm anders, als dass der RuntimeError nicht passiert, stattdessen bekomme ich die Verwendungshinweise für mein Programm immer wieder auf den cmd geschrieben, nehme ich an der erzeugten Prozesse, die versuchen, die EXE selbst zu nennen, was offensichtlich nicht ist, was passieren soll.

Unnötig zu sagen, das Programm läuft ohne Probleme als .py-Skript.

Ich bin mit 32-Bit-Python 3.4 auf Windows 10.

Die einzige andere Lösung (haben die gleiche Multithreading Problem mit Python 2.7 als auch hatte) ich denken kann, meine Lösung neu zu schreiben ist Multiprozessing zu verwenden. Prozess statt Multiprocessing.Pool, da scheint es eine Lösung zu geben. Wenn Sie einen ziemlich geringen Aufwand haben, um das zu tun, was meine Pool-Funktion macht, werde ich mich damit zufrieden geben.

+0

Hallo @Mjellma könnten Sie bitte eine Antwort auf Ihre Frage geben? Ich verstehe, dass Sie mit diesem Fehler umgehen konnten. – mathiasfk

Antwort

1

Haben Sie eine Lösung für Ihr Problem gefunden? Ich habe das gleiche Problem, aber ich habe es geschafft, es mit einem einfachen Code arbeiten zu lassen. Es funktioniert jedoch noch nicht mit meiner vollständigen Codierung (mit sklearn). Wenn es Ihnen gelingt, es zum Laufen zu bringen, lassen Sie es mich wissen, es könnte mir auch helfen.

hier ist die Codierung, die für mich gearbeitet:

import multiprocessing 
import time 

def func (param1, param2): 
    print ("hello " + str (param1)) 
    time.sleep (param2) 
    print ("Hello again " + str (param1)) 
    return "test " + str (param1) 

def main(): 
    lParams = [("test1", 3), 
       ("test2", 2), 
       ("test3", 1)] 
    args = [] 
    for param1, param2 in lParams: 
     tup = (param1, param2) 
     args.append (tup) 

    with multiprocessing.Pool (multiprocessing.cpu_count()) as p: 
     results = [p.apply_async (func, a) for a in args] 
     for r in results: 
      print ("Returned " + r.get()) 

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

Bitte beachte, dass ich die „-D“ Option in pyinstaller bin mit (einem Verzeichnis) meine Anwendung zu kompilieren.

+0

Was für mich funktionierte, war das Importieren von Bibliotheken im Funktionsumfang und außerhalb des globalen Namensraums. Da das vor einer Weile her ist, kann ich mich nicht mehr an den Grund erinnern, aber ich erinnere mich, dass mich bewegende Bibliothekseinfuhren an einen Ort brachten, wo ich fortfahren und mein Projekt schließlich beenden konnte. Wenn das nicht hilft und Sie immer noch das Problem haben, lassen Sie es mich wissen und ich kann den Code immer mit Ihnen teilen, so dass Sie genauer hinsehen können, der Punkt ist, dass es irgendwie am Ende funktionierte. – Mjellma