Si hagodatos Volviendo de procesos bifurcados
Process.fork do
x
end
¿Cómo puedo saber lo que x Se volvió (por ejemplo, verdadero/fase/cadena)?
(Escribir en un fichero/base de datos no es una opción ...)
Si hagodatos Volviendo de procesos bifurcados
Process.fork do
x
end
¿Cómo puedo saber lo que x Se volvió (por ejemplo, verdadero/fase/cadena)?
(Escribir en un fichero/base de datos no es una opción ...)
Envolví en ruby parallel gem todas las soluciones que encontré en el camino (algunos otros problemas como el usuario que sale + búferes de tuberías). Ahora es tan fácil como:
results = Parallel.map([1,2,3],:in_processes=>4) do |i|
execute_something(i)
end
o
results = Parallel.map([1,2,3],:in_threads=>4) do |i|
execute_something(i)
end
De acuerdo con la documentación:
Si se especifica un bloque, bloque que se ejecuta en el subproceso y el el subproceso termina con un estado de cero.
Así que si usted lo llama con un bloque, devuelve 0. De lo contrario, funciona básicamente igual que la llamada fork()
sistema en Unix (el padre recibe el PID del nuevo proceso, el niño recibe nil
).
¿Cómo puede esta ayuda para conseguir lo que la 'x' regresado? – grosser
El proceso hijo se ejecuta en un proceso separado (obviamente), por lo que para obtener el valor de cualquier "x", probablemente tendrá que comunicarse a través de sockets, pipes o algo similar. Dudo que pueda, por ejemplo, establecer variables dentro del bloque que se reflejan fuera del bloque, ya que el proceso secundario tiene memoria separada, etc. – mipadi
La comunicación de la horquilla entre dos procesos Unix es principalmente el código de retorno y nada más. Sin embargo, podría abrir un descriptor de archivo entre los dos procesos y pasar datos entre los procesos a través de este descriptor de archivo: esta es la forma normal de conexión de Unix.
Si pasa los valores de Marshal.dump() y Marshal.load(), puede pasar fácilmente objetos de Ruby entre esos procesos de Ruby.
Puede usar la memoria compartida para hacer esto si el niño solo necesita una pequeña porción de código ruby. Algo así como el siguiente trabajo:
str = 'from parent'
Thread.new do
str = 'from child'
end
sleep(1)
puts str # outputs "from child"
concurrencia puede ser bastante complicado, sin embargo, y el acceso a la memoria compartida de esta manera es una gran parte de la razón - en cualquier momento que tenga una variable y otro proceso puede cambiarlo fuera de ti, deberías ser muy cauteloso. Alternativamente, puede usar una tubería, que es más engorrosa pero probablemente más segura para cualquier código que no sea el más trivial, y también se puede usar para ejecutar cualquier comando arbitrario. He aquí un ejemplo, directamente de la rdoc para IO.popen:
f = IO.popen("uname")
p f.readlines # outputs "Darwin", at least on my box :-)
En realidad sólo tenía que manejar este problema en Rails isolation testing. Publiqué sobre eso algunos on my blog.
Básicamente, lo que quiere hacer es abrir una tubería en el padre y el hijo, y hacer que el niño escriba en la tubería. Aquí está una manera simple de ejecutar el contenido de un bloque en un proceso hijo y volver el resultado:
def do_in_child
read, write = IO.pipe
pid = fork do
read.close
result = yield
Marshal.dump(result, write)
exit!(0) # skips exit handlers.
end
write.close
result = read.read
Process.wait(pid)
raise "child failed" if result.empty?
Marshal.load(result)
end
Posteriormente, se podría ejecutar:
do_in_child do
require "some_polluting_library"
SomePollutingLibrary.some_operation
end
Tenga en cuenta que si lo hace un requieren en el niño , no tendrá acceso a esa biblioteca en el padre, por lo que no puede devolver un objeto de ese tipo con este método. Sin embargo, puede devolver cualquier tipo que esté disponible en ambos.
También tenga en cuenta que muchos de los detalles aquí (read.close
, Process.wait2(pid)
) son en su mayoría detalles de la economía doméstica, por lo que si utiliza esto mucho probablemente debería moverlo a una biblioteca de utilidad que puede volver a utilizar.
Finalmente, tenga en cuenta que esto no funcionará en Windows o JRuby, ya que no son compatibles con el bifurcación.
Gracias por todas las respuestas, tengo mi solución en funcionamiento, todavía necesitan ver cómo manejar entornos no se bifurcan, pero por ahora funciona :)
read, write = IO.pipe
Process.fork do
write.puts "test"
end
Process.fork do
write.puts 'test 2'
end
Process.wait
Process.wait
write.close
puts read.read
read.close
se puede ver en acción @parallel_specs Rails plugin
¿Ha visto el enlace de la prueba de aislamiento que proporcioné en mi respuesta? Maneja entornos de bifurcación y no bifurcación, y puede que ya haga todo lo que necesita. –
¡Sí, también leí su publicación al respecto, añadiré esto pronto! – grosser
sí, se puede crear un subproceso para ejecutar un bloque interior.
recomiendo the aw
gem:
Aw.fork! { 6 * 7 } # => 42
Por supuesto, se impide efectos secundarios:
arr = ['foo']
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"]
arr # => ["foo"]
¿Puede pasar objetos, o incluso clases, como parámetros aquí? Realmente podría usar una forma de bifurcar un proceso y pasarle un entorno completo. – Automatico