Jeśli robięZwracanie danych z rozdwojonych procesów
Process.fork do
x
end
jak mogę wiedzieć co x zwrócone (np true/fase/string)?
(Zapis do pliku/bazy danych nie jest rozwiązaniem ...)
Jeśli robięZwracanie danych z rozdwojonych procesów
Process.fork do
x
end
jak mogę wiedzieć co x zwrócone (np true/fase/string)?
(Zapis do pliku/bazy danych nie jest rozwiązaniem ...)
Zawinęłem wszystkie rozwiązania, które znalazłem po drodze (niektóre inne problemy, takie jak wyjście użytkownika + bufory przewodów) do ruby parallel gem. Teraz jest to tak proste, jak:
results = Parallel.map([1,2,3],:in_processes=>4) do |i|
execute_something(i)
end
lub
results = Parallel.map([1,2,3],:in_threads=>4) do |i|
execute_something(i)
end
Zgodnie z dokumentacją:
Jeśli blok jest określone, że blok jest uruchamiany w podproces oraz podproces kończy się stanem zero.
Więc jeśli nazywają go z bloku, zwraca 0. W przeciwnym razie, działa w zasadzie tak samo jak wywołanie systemowe fork()
na Unix (rodzic odbiera PID nowego procesu, dziecko otrzymuje nil
).
Jak to może pomóc w osiągnięciu tego, co 'x' wrócił? – grosser
Proces potomny działa w oddzielnym procesie (oczywiście), więc aby uzyskać wartość dowolnego "x", prawdopodobnie będziesz musiał komunikować się przez gniazda, potoki lub coś podobnego. Wątpię, abyś mógł np. Ustawić zmienne wewnątrz bloku, które znajdują odzwierciedlenie poza blokiem, ponieważ proces potomny ma osobną pamięć itd. – mipadi
Komunikacja widelca między dwoma procesami uniksowymi to głównie kod powrotu i nic więcej. Można jednak otworzyć plik rejestru między dwoma procesami i przekazać dane między procesami przez ten plik-rejestrator: jest to normalny sposób działania Uniksa.
Jeśli przekażesz wartości Marshal.dump() i Marshal.load(), możesz łatwo przekazać obiekty Ruby pomiędzy tymi procesami Ruby.
Możesz użyć pamięci współdzielonej, aby to zrobić, jeśli dziecko musi być małym kawałkiem kodu ruby. Coś jak poniżej będzie działać:
str = 'from parent'
Thread.new do
str = 'from child'
end
sleep(1)
puts str # outputs "from child"
współbieżności może być dość trudne, chociaż, i dostępu do pamięci współdzielonej w ten sposób jest duża część z tego powodu - za każdym razem masz zmienną i inny proces może go zmienić od ciebie, powinieneś być bardzo ostrożny. Alternatywnie możesz użyć potoku, który jest bardziej uciążliwy, ale prawdopodobnie bezpieczniejszy dla dowolnego, ale najbardziej banalnego kodu, i może być również użyty do uruchomienia dowolnych poleceń. Oto przykład, prosto z rdoc dla IO.popen:
f = IO.popen("uname")
p f.readlines # outputs "Darwin", at least on my box :-)
My właściwie tylko musiał obsługiwać ten problem w Rails isolation testing. Opublikowalem o tym około on my blog.
Zasadniczo, co chcesz zrobić, to otworzyć potok w rodzicu i podrzędnym, i niech dziecko napisze do fajki. Oto prosty sposób uruchomić zawartość bloku w procesie potomnym i wrócić Rezultat:
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
Następnie można uruchomić:
do_in_child do
require "some_polluting_library"
SomePollutingLibrary.some_operation
end
Zauważ, że jeśli zrobić wymagają u dziecka , nie będziesz mieć dostępu do tej biblioteki w obiekcie nadrzędnym, więc nie możesz zwrócić obiektu tego typu za pomocą tej metody. Możesz jednak zwrócić dowolny typ, który jest dostępny w obu.
Należy również pamiętać, że wiele szczegółów tutaj (read.close
, Process.wait2(pid)
) to głównie szczegóły dotyczące sprzątania, więc jeśli korzystasz z tego dużo, prawdopodobnie powinieneś przenieść to do biblioteki narzędziowej, którą możesz ponownie wykorzystać.
Na koniec zwróć uwagę, że to nie zadziała w systemie Windows lub JRuby, ponieważ nie obsługuje rozwidlania.
Dzięki za wszystkie odpowiedzi, mam moje rozwiązanie działa, nadal trzeba zobaczyć, jak radzić sobie środowisk spoza rozwidlone, ale na razie to działa :)
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
można zobaczyć go w akcji @parallel_specs Rails plugin
Czy widziałeś w moim odpowiedzi link testowy izolacji? Obsługuje zarówno środowiska rozwidlające się, jak i nie-rozwidlające i może już robić wszystko, czego potrzebujesz. –
Tak, przeczytaj także swój wpis na ten temat, źle dodaj to wkrótce! – grosser
Tak, można utworzyć podproces aby wykonać blok wewnątrz.
Polecam the aw
gem:
Aw.fork! { 6 * 7 } # => 42
oczywiście, zapobiega skutki uboczne:
arr = ['foo']
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"]
arr # => ["foo"]
Czy można przekazywać obiekty, a nawet klasy, jako parametry tutaj? Naprawdę mógłbym użyć sposobu na rozwidlenie procesu i przekazanie mu całego środowiska. – Automatico