¿Es posible ejecutar la función en un subproceso sin enhebrar o escribir un archivo / script separado?

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

Solo he encontrado documentación sobre la apertura de subprocesos utilizando scripts separados. ¿Alguien sabe cómo pasar objetos de función o incluso una forma fácil de pasar código de función?

wroscoe
fuente
1
Creo que estás buscando el módulo de multiprocesamiento .
Noctis Skytower

Respuestas:

111

Creo que está buscando algo más parecido al módulo de multiprocesamiento:

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

El módulo de subproceso es para generar procesos y hacer cosas con su entrada / salida, no para ejecutar funciones.

Aquí hay una multiprocessingversión de su código:

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
fuente
20
Puede usar el processifydecorador como atajo: gist.github.com/2311116
schlamar
3
¿Supongo que esto clona el intérprete de Python y todo su entorno para el subproceso?
Jens
1
Aquí hay una bifurcación de processify que funciona en python 3 y admite funciones de generador. gist.github.com/stuaxo/889db016e51264581b50
Stuart Axon
4
Tenga en cuenta que este código contiene un interbloqueo en caso de que esté pasando datos no trivialmente grandes a través de la cola; siempre queue.get () antes de unirse al proceso, de lo contrario, se quedará intentando escribir en la cola mientras nada lo lee.
Petr Baudis
@schlamar Quiero ejecutar una función en segundo plano, pero tengo algunas limitaciones de recursos y no puedo ejecutar la función tantas veces como quiero y quiero poner en cola las ejecuciones adicionales de la función. ¿Tienes alguna idea de cómo debería hacer eso? Aquí tengo mi pregunta . ¿Podría echar un vistazo a mi pregunta? ¡Cualquier ayuda sería genial!
Amir
17

Puede utilizar la forkllamada estándar del sistema Unix , como os.fork(). fork()creará un nuevo proceso, con el mismo script en ejecución. En el nuevo proceso, devolverá 0, mientras que en el proceso anterior devolverá el ID de proceso del nuevo proceso.

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

Para una biblioteca de nivel superior, que proporciona soporte de multiprocesamiento que proporciona una abstracción portátil para usar múltiples procesos, está el módulo de multiprocesamiento . Hay un artículo sobre IBM DeveloperWorks, Multiprocesamiento con Python , con una breve introducción a ambas técnicas.

Brian Campbell
fuente
Soy curioso; ¿Por qué el voto negativo? ¿Hay algo de malo en mi respuesta?
Brian Campbell
El multiprocesamiento no es solo una envoltura de nivel superior alrededor de fork (), es un kit de herramientas multiprocesamiento multiplataforma (que usa fork en Unix). Lo cual es importante, porque esto significa que se ejecuta, digamos, en Windows, mientras que fork () no. Editar: Y este fue el motivo del voto negativo, aunque luego decidí que probablemente no valía la pena. Sin embargo, es demasiado tarde para retirarlo. Edit2: O más bien, la razón fue la sugerencia de fork () cuando no es multiplataforma.
Devin Jeanpierre
3
@Devin, siempre puedes retirar un voto negativo que hiciste, si quieres.
Alex Martelli
Editado para aclarar eso, entonces. Mencioné explícitamente que forkno es portátil; Por lo general, daré respuestas no portátiles junto con información de que no son portátiles y dejaré que el interrogador decida si eso es suficiente para ellos. Como he editado mi respuesta, debería poder eliminar el voto negativo si cree que lo he mejorado lo suficiente; aunque no hay resentimientos si no lo haces, solo quería comprobar qué había hecho mal.
Brian Campbell
@ Alex, no, no puedes. Después de que pase una cierta cantidad de tiempo, no puede retirarlo hasta que se realice una edición. Había pasado tanto tiempo antes de que lo reconsiderara, de ahí el comentario "demasiado tarde". De todos modos, como dije, había decidido que no valía la pena, así que se fue. También aprecio y entiendo tus razones, y me alegra que no haya resentimientos de cualquier manera. : p
Devin Jeanpierre
5

La publicación anterior de Brian McKenna sobre multiprocesamiento es realmente útil, pero si desea seguir la ruta del subproceso (a diferencia de la basada en procesos), este ejemplo lo ayudará a comenzar:

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" 

También puede utilizar la setDaemon(True)función para poner en segundo plano el hilo inmediatamente.

Alexis Benoist
fuente