Ist es möglich, eine Funktion in einem Unterprozess auszuführen, ohne eine separate Datei / ein separates Skript einzufädeln oder zu schreiben?

82
import subprocess

def my_function(x):
    return x + 100

output = subprocess.Popen(my_function, 1) #I would like to pass the function object and its arguments
print output 
#desired output: 101

Ich habe nur Dokumentation zum Öffnen von Unterprozessen mit separaten Skripten gefunden. Weiß jemand, wie man Funktionsobjekte übergibt oder wie man Funktionscode einfach übergibt?

Wroscoe
quelle
1
Ich glaube, dass Sie nach dem Multiprozessor- Modul suchen .
Noctis Skytower

Antworten:

111

Ich denke, Sie suchen eher nach dem Multiprozessor-Modul:

http://docs.python.org/library/multiprocessing.html#the-process-class

Das Unterprozessmodul dient zum Laichen von Prozessen und zum Ausführen von Aufgaben mit ihrer Eingabe / Ausgabe - nicht zum Ausführen von Funktionen.

Hier ist eine multiprocessingVersion Ihres Codes:

from multiprocessing import Process, Queue

def my_function(q, x):
    q.put(x + 100)

if __name__ == '__main__':
    queue = Queue()
    p = Process(target=my_function, args=(queue, 1))
    p.start()
    p.join() # this blocks until the process terminates
    result = queue.get()
    print result
Brian McKenna
quelle
20
Sie können den processifyDekorateur als Verknüpfung verwenden: gist.github.com/2311116
schlamar
3
Ich gehe davon aus, dass dies den Python-Interpreter und seine gesamte Umgebung für den Unterprozess klont.
Jens
1
Hier ist eine Verzweigung von processify, die in Python 3 funktioniert und Generatorfunktionen unterstützt. gist.github.com/stuaxo/889db016e51264581b50
Stuart Axon
4
Beachten Sie, dass dieser Code einen Deadlock enthält, falls Sie nicht trivial große Datenmengen durch die Warteschlange leiten - immer queue.get (), bevor Sie sich dem Prozess anschließen. Andernfalls bleibt der Versuch bestehen, in die Warteschlange zu schreiben, während nichts sie liest.
Petr Baudis
@schlamar Ich möchte eine Funktion im Hintergrund ausführen, habe jedoch einige Ressourcenbeschränkungen und kann die Funktion nicht so oft ausführen, wie ich möchte, und möchte die zusätzlichen Ausführungen der Funktion in die Warteschlange stellen. Hast du eine Idee, wie ich das machen soll? Ich habe meine Frage hier . Könnten Sie sich bitte meine Frage ansehen? Jede Hilfe wäre toll!
Amir
17

Sie können den Standard-Unix- forkSystemaufruf als verwenden os.fork(). fork()erstellt einen neuen Prozess mit demselben Skript. Im neuen Prozess wird 0 zurückgegeben, während im alten Prozess die Prozess-ID des neuen Prozesses zurückgegeben wird.

child_pid = os.fork()
if child_pid == 0:
  print "New proc"
else:
  print "Old proc"

Für eine übergeordnete Bibliothek, die Multiprocessing-Unterstützung bietet und eine portable Abstraktion für die Verwendung mehrerer Prozesse bietet, gibt es das Multiprocessing- Modul. Es gibt einen Artikel über IBM DeveloperWorks, Multiprocessing with Python , mit einer kurzen Einführung in beide Techniken.

Brian Campbell
quelle
Ich bin neugierig; Warum die Gegenstimme? Stimmt etwas mit meiner Antwort nicht?
Brian Campbell
Multiprocessing ist nicht nur ein Wrapper auf höherer Ebene um fork (), sondern ein Multiplattform-Multiprocessing-Toolkit (das Fork unter Unix verwendet). Was wichtig ist, da dies bedeutet, dass es beispielsweise unter Windows ausgeführt wird, während dies bei fork () nicht der Fall ist. Edit: Und das war der Grund für die Ablehnung, obwohl ich später entschieden habe, dass es sich wahrscheinlich nicht gelohnt hat. Es ist jedoch zu spät, um es zurückzunehmen. Edit2: Oder besser gesagt, fork () wurde vorgeschlagen, wenn es nicht plattformübergreifend ist.
Devin Jeanpierre
3
@Devin, du kannst jederzeit eine Downvote zurücknehmen, wenn du willst.
Alex Martelli
Bearbeitet, um das zu verdeutlichen. Ich habe ausdrücklich erwähnt, dass dies forknicht portabel ist. Ich werde im Allgemeinen nicht tragbare Antworten zusammen mit Informationen geben, dass sie nicht tragbar sind, und den Fragesteller entscheiden lassen, ob dies für sie ausreicht. Da ich meine Antwort bearbeitet habe, sollten Sie in der Lage sein, das Downvote zu entfernen, wenn Sie der Meinung sind, dass ich es ausreichend verbessert habe. Obwohl es keine harten Gefühle gibt, wollte ich nur überprüfen, was ich falsch gemacht habe.
Brian Campbell
@ Alex, nein, das kannst du nicht. Nach Ablauf einer bestimmten Zeit können Sie diese erst zurücknehmen, wenn eine Bearbeitung erfolgt. Eine solche Zeit war vergangen, bevor ich überlegte, daher der "zu späte" Kommentar. Wie gesagt, ich hatte entschieden, dass es sich nicht lohnt, also ist es weg. Ich schätze und verstehe auch Ihre Gründe und bin froh, dass es so oder so keine harten Gefühle geben würde. : p
Devin Jeanpierre
5

Der obige Beitrag von Brian McKenna über Multiprocessing ist wirklich hilfreich. Wenn Sie jedoch den Thread-Weg einschlagen möchten (im Gegensatz zu prozessbasiert), können Sie mit diesem Beispiel beginnen:

import threading
import time

def blocker():
    while True:
        print "Oh, sorry, am I in the way?"
        time.sleep(1)

t = threading.Thread(name='child procs', target=blocker)
t.start()

# Prove that we passed through the blocking call
print "No, that's okay" 

Sie können die setDaemon(True)Funktion auch verwenden, um den Thread sofort als Hintergrund zu verwenden.

Alexis Benoist
quelle