2009-10-22 12 views
8

W mojej aplikacji Ruby on Rails muszę wykonywać równolegle 50 zadań tła. Każde zadanie tworzy połączenie TCP z innym serwerem, udostępnia niektóre dane i aktualizuje aktywny obiekt rekordu.Praca z wieloma równoległymi zadaniami z Railsami

Znam różne rozwiązania, aby wykonać to zadanie, ale którekolwiek z nich równolegle. Na przykład delayed_job (DJ) może być doskonałym rozwiązaniem, jeśli tylko może wykonywać wszystkie zadania równolegle.

Wszelkie pomysły? Dzięki.

+0

Innym rozwiązaniem tutaj: http://stackoverflow.com/questions/16551466/parallelizing-methods-in-rails/16676981#16676981 – Subhas

+0

Ciekawe, dziękuję @RDX – fjyaniez

Odpowiedz

1

Niektóre myśli ...

  • Tylko dlatego trzeba przeczytać 50 stron i naturalnie chcą niektórzy równoległa praca robi nie średnią że potrzebujesz 50 procesów lub wątków. Musisz zrównoważyć spowolnienie i obciążenie. Co powiesz na to, że każdy z 10 lub 20 procesów czyta kilka stron?

  • zależności od Ruby używasz, uważać na zielonych wątków, może nie uzyskać równoległy rezultat chcesz

  • Może chcesz zorganizować ją jak rewers, po stronie klienta inetd i użyj connect_nonblock i IO.select, aby uzyskać połączenia równoległe, które chcesz, przez równoległe działanie wszystkich serwerów. Tak naprawdę nie potrzebujesz równoległego przetwarzania wyników, wystarczy ustawić się równolegle na wszystkich serwerach, ponieważ właśnie tam naprawdę jest opóźnienie.

Tak, coś w tym z biblioteki gniazda ... przedłużyć go do wielu wybitnych połączeń ...

require 'socket' 
include Socket::Constants 
socket = Socket.new(AF_INET, SOCK_STREAM, 0) 
sockaddr = Socket.sockaddr_in(80, 'www.google.com') 
begin 
    socket.connect_nonblock(sockaddr) 
    rescue Errno::EINPROGRESS 
    IO.select(nil, [socket]) 
    begin 
    socket.connect_nonblock(sockaddr) 
    rescue Errno::EISCONN 
    end 
end 
socket.write("GET/HTTP/1.0\r\n\r\n") 
# here perhaps insert IO.select. You may not need multiple threads OR multiple 
# processes with this technique, but if you do insert them here 
results = socket.read 
+0

IO.select może być przydatna w tym przypadku, spróbuję. Dziękuję Ci. – fjyaniez

6

W rzeczywistości jest możliwe uruchomienie wielu pracowników delayed_job.

Od http://github.com/collectiveidea/delayed_job:

# Runs two workers in separate processes. 
$ RAILS_ENV=production script/delayed_job -n 2 start 
$ RAILS_ENV=production script/delayed_job stop 

więc, teoretycznie, może po prostu wykonać:

$ RAILS_ENV=production script/delayed_job -n 50 start 

To będzie tarło 50 procesów, jednak nie jestem pewien, czy to byłoby zalecane w zależności od zasoby systemu, w którym to uruchamiasz.


Alternatywną opcją byłoby użycie threads. Po prostu utwórz nowy wątek dla każdego zadania.

Jedną rzeczą do zapamiętania jest ta metoda polegająca na tym, że ActiveRecord nie jest bezpieczny dla wątków. Można zrobić to bezpieczny wątku stosując następujące ustawienia:

ActiveRecord::Base.allow_concurrency = true 
+0

Można również uruchomić delayed_job pracowników na wielu maszynach. Wątpię, byś zyskał wiele korzyści z uruchamiania większej liczby robotników na jednej maszynie niż rdzenie procesora, ale możesz rozłożyć obciążenie, uruchamiając go na kilku skrzynkach. Jeśli chcesz uruchomić 50 jednocześnie, myślę, że będziesz musiał rozpowszechniać pracę. –

+2

Otrzymam świadczenie wielu pracowników na jednej maszynie, ponieważ większość pracowników będzie zablokowana przez IO – fjyaniez

0

Ponieważ pracujemy z szyn, radzę używać delayed_job zrobić to zamiast dzielić na nici lub widelce. Powód - zajmowanie się timeoutami i innymi rzeczami, gdy przeglądarka czeka, może być prawdziwym bólem. Istnieją dwa podejścia, które można podjąć z DJ-em

Pierwszym z nich jest odrodzenie 50+ pracowników. W zależności od środowiska może to być dość ciężkie rozwiązanie, ale działa świetnie.Następnie, gdy musisz uruchomić swoją pracę, po prostu upewnij się, że tworzysz 50 unikalnych zadań. Jeśli masz zbyt dużo pamięci i chcesz robić to w ten sposób, stwórz oddzielne środowisko, które zostanie rozebrane, specjalnie dla twoich pracowników.

Drugi sposób polega na utworzeniu pojedynczego zadania, które używa Curl :: Multi do obsługi 50 równoczesnych żądań TCP. Możesz dowiedzieć się więcej na ten temat tutaj: http://curl-multi.rubyforge.org/ W ten sposób możesz mieć jeden procesor działający w tle, obsługujący wszystkie twoje żądania TCP równolegle.