2010-06-16 13 views
9

Mam program Ruby, który ładuje dwa bardzo duże pliki yaml, więc mogę uzyskać przyspieszenie, korzystając z wielu rdzeni poprzez rozwidlenie niektórych procesów. Próbowałem już wyglądać, ale mam problem z ustaleniem, w jaki sposób, a nawet jeśli, mogę udostępniać zmienne w różnych procesach.Współdzielona zmienna między procesami Ruby

Poniższy kod jest co obecnie mam:

@proteins = "" 
@decoyProteins = "" 

fork do 
    @proteins = YAML.load_file(database) 
    exit 
end 

fork do 
    @decoyProteins = YAML.load_file(database) 
    exit 
end 

p @proteins["LVDK"] 

P wyświetlacze nil choć ze względu na widelcu.

Czy możliwe jest podzielenie zmiennych na procesy rozwidlone? A jeśli tak, to w jaki sposób?

+0

Czy jesteś pewien, że to YAML zabiera trochę czasu? Jeśli tak, czy próbowałeś załadować go za pomocą Psych, a nie Syck? –

Odpowiedz

13

Jednym z problemów jest konieczność użycia Process.wait, aby poczekać na zakończenie rozwidlonych procesów. Drugi polega na tym, że nie można wykonywać komunikacji międzyprocesowej za pomocą zmiennych. Aby to zobaczyć:

@one = nil 
@two = nil 
@hash = {} 
pidA = fork do 
    sleep 1 
    @one = 1 
    @hash[:one] = 1 
    p [:one, @one, :hash, @hash] #=> [ :one, 1, :hash, { :one => 1 } ] 
end 
pidB = fork do 
    sleep 2 
    @two = 2 
    @hash[:two] = 2 
    p [:two, @two, :hash, @hash] #=> [ :two, 2, :hash, { :two => 2 } ] 
end 
Process.wait(pidB) 
Process.wait(pidA) 
p [:one, @one, :two, @two, :hash, @hash] #=> [ :one, nil, :two, nil, :hash, {} ] 

Jednym ze sposobów komunikacji międzyprocesorowej jest użycie rury (IO::pipe). Otwórz go przed rozwidleniem, a następnie po obu stronach widelca zamknij jeden koniec rury.

Od ri IO::pipe:

rd, wr = IO.pipe 

    if fork 
     wr.close 
     puts "Parent got: <#{rd.read}>" 
     rd.close 
     Process.wait 
    else 
     rd.close 
     puts "Sending message to parent" 
     wr.write "Hi Dad" 
     wr.close 
    end 

_produces:_ 

    Sending message to parent 
    Parent got: <Hi Dad> 

Jeśli chcesz podzielić zmienne używać wątków:

@one = nil 
@two = nil 
@hash = {} 
threadA = Thread.fork do 
    sleep 1 
    @one = 1 
    @hash[:one] = 1 
    p [:one, @one, :hash, @hash] #=> [ :one, 1, :hash, { :one => 1 } ] # (usually) 
end 
threadB = Thread.fork do 
    sleep 2 
    @two = 2 
    @hash[:two] = 2 
    p [:two, @two, :hash, @hash] #=> [ :two, 2, :hash, { :one => 1, :two => 2 } ] # (usually) 
end 
threadA.join 
threadB.join 
p [:one, @one, :two, @two, :hash, @hash] #=> [ :one, 1, :two, 2, :hash, { :one => 1, :two => 2 } ] 

Jednak nie jestem pewien, czy będzie Ci gwintowania żadnych korzyści, gdy jesteś IO granica.

+0

Skąd się bierze symbol ': hash', gdy piszesz' p [: one, @one,: hash, @hash] # => [: one, 1, {: one => 1}] '? – Jeriko

+0

... niewidoczny z powodu złej transkrypcji? :) naprawiono, thx – rampion

+0

Jak udostępnić dane między procesami, które uruchamia inicjalizatory Rails i proces, który uruchamia żądania HTTP? Wszystkie są odradzane przez Phusion Passenger bez mojej ingerencji. – Paul

0

Możliwe jest udostępnianie zmiennych między procesami; DRuby jest prawdopodobnie najniższym sposobem, aby to zrobić.

+0

doc: http://www.ensta.fr/~diam/ruby/online/ruby-doc-stdlib/libdoc/drb/rdoc/classes/DRb.html – rampion

0

Prawdopodobnie chcesz użyć wątku zamiast widelca, jeśli chcesz udostępnić dane.

http://ruby-doc.org/docs/ProgrammingRuby/html/tut_threads.html

Aha, i jeśli naprawdę chcesz, aby skorzystać z wątków będziemy chcieli użyć JRuby. W [c] Ruby 1.9 możesz zawsze chcieć spojrzeć na włókna. Nie patrzyłem jednak na nich, nie wiem, czy to rozwiązanie dla ciebie.

+1

Nic nie jest tym, czego chcę, ponieważ nie skorzystaj z wielu rdzeni. Rzeczywiście próbowałem wątków już i było to wolniejsze. –

1

Cod jest przeznaczony do komunikacji między procesami i pozwala na łatwe wysyłanie danych między rozwidlonymi procesami.

Powiązane problemy