2012-11-12 8 views
5

Szukałem optymalizacji programu ruby, który jest dość intensywny w obliczeniach na wielu danych. Nie znam C i wybrałem Ruby (nie, że znam to dobrze) i jestem całkiem zadowolony z wyników, z wyjątkiem czasu, który trzeba wykonać. Jest dużo danych i bez wydawania pieniędzy chciałbym wiedzieć, co mogę zrobić, aby upewnić się, że maksymalizuję własne zasoby systemowe.Tworzenie programu ruby ​​na wszystkich procesorach

Kiedy uruchamiam podstawowy program typu Ruby, używa on pojedynczego procesora? Jeśli nie przypisałem specjalnie zadań do procesora, Ruby nie przeczyta mojego programu i nie załaduje magicznie każdego procesora, aby ukończyć program tak szybko, jak to możliwe, prawda? Zakładam, że nie ...

Czytałem trochę o przyspieszaniu Rubiego, aw innym wątku czytałem, że Ruby nie obsługuje prawdziwej wielowątkowości (chociaż mówiło, że robi to JRuby). Ale gdybym miał "zepsuć" mój program na dwie części, które mogą być uruchamiane w oddzielnych instancjach i uruchamiać je w parralelu ... czy te dwie części automatycznie uruchomiłyby się na dwóch oddzielnych procesorach? Gdybym miał cztery procesory i otworzył cztery powłoki i uruchomił cztery oddzielne części (1/4) programu - czy zakończyłby się za 1/4 czasu?

Aktualizacja

Po przeczytaniu komentarzy postanowiłem dać jruby strzał. Przeniesienie aplikacji nie było trudne. Nie użyłem jeszcze "brzoskwini", ale po prostu uruchamiając go w JRuby, aplikacja działa w 1/4 czasu !!! Szalony. Nie spodziewałem się tak dużej zmiany. Pójść, aby dać .peach strzał i zobacz, jak to poprawia rzeczy. Nadal nie mogę uwierzyć w to wzmocnienie.

Aktualizacja # 2

Właśnie dałem brzoskwini spróbować. Skończyło się golenie o 15% taniej. Dlatego warto było przejść na JRuby i używając Peacha.

Dziękuję wszystkim!

+0

Nie widząc kodu źródłowego, zgadujemy, co można zrobić, aby przyspieszyć działanie aplikacji. Możliwe jednak, że uda się go trochę przyspieszyć, jeśli robisz coś trudnego/powolnego. –

Odpowiedz

4

Użyj klejnotu JRuby i klejnotu peach i nie może być łatwiejsze. Po prostu wymień .each na .peach i uruchom, równolegle. Są też dodatkowe opcje, które kontrolują dokładnie, ile wątków zostało zainicjowanych, itp. Użyłem tego i działa świetnie.

zbliżyć do n czasy przyspieszenia, gdzie n jest liczba procesorów/rdzeni dostępnych. Uważam, że optymalna liczba wątków jest nieco większa niż liczba procesorów/rdzeni.

0

Nawlekanie jest zwykle uważane za jeden ze słabych punktów Ruby, ale zależy to od tego, z której wersji Ruby korzystasz.

Naprawdę dobrym zapisem na temat różnych modeli gwintowania jest "Does ruby have real multithreading?".

Z mojego doświadczenia i z tego, co zebrałem od ludzi, którzy wiedzą lepiej o tych rzeczach, wydaje się, że jeśli wybierzesz implementację Ruby, JRuby jest drogą do zrobienia. Chociaż, jeśli uczysz się Ruby, możesz wybrać inny język, taki jak Erlang, lub Clojure, które są popularnymi wyborami, jeśli chcesz używać JVM.

0

Tak miły jak rubin, nie jest znany ze swojej szybkości wykonania. Biorąc to pod uwagę, jeśli, jak zaznaczono w twoim komentarzu, możesz podzielić dane wejściowe na fragmenty o jednakowej wielkości, powinieneś być w stanie uruchomić n instancji programu, gdzie n to liczba rdzeni, które masz, a system operacyjny zaopiekuj się użyciem dla ciebie wszystkich rdzeni.

W najlepszym przypadku byłby uruchamiany za 1/n czasu, ale tego typu rzeczy mogą być trudne, ponieważ niektóre części systemu, takie jak pamięć, muszą być współdzielone między procesami i rywalizacja między nimi. procesy mogą powodować skalowanie liniowe. Jeśli podział jest łatwy do zrobienia, spróbuję. Możesz także po prostu spróbować uruchomić dwa razy ten sam program i sprawdzić, ile czasu potrzeba na jego uruchomienie, jeśli trwa to tyle samo czasu, ile trzeba, aby uruchomić dwa, prawdopodobnie wszystkie są ustawione, po prostu podziel dane i przejdź do to.

Wypróbowanie juby i niektórych wątków prawdopodobnie pomogłoby, ale to dodało sporo złożoności. (To prawdopodobnie byłaby dobra wymówka, żeby dowiedzieć się więcej o wątkach.)

2

Podobnie jak inni mówili, że implementacja MRI ruby ​​(ta, której używa większość ludzi) nie obsługuje natywnych wątków. Dlatego nie można dzielić pracy między rdzeniami procesora, uruchamiając więcej wątków za pomocą implementacji MRI.

Jednak jeśli twój proces jest związany z IO (na przykład ograniczony przez dysk lub aktywność sieciową), możesz nadal korzystać z wielu wątków MRI.

JRuby z drugiej strony obsługuje wątki natywne, co oznacza, że ​​można używać wątków do dzielenia pracy między rdzeniami procesora.

Ale wszystko nie jest stracone. Dzięki MRI (i wszystkim innym implementacjom ruby), możesz nadal używać procesów do dzielenia pracy.

Można to zrobić za pomocą Process.fork na przykład tak:

Process.fork { 
    10.times { 
    # Do some work in process 1 
    sleep 1 
    puts "Hello 1" 
    } 
} 

Process.fork { 
    10.times { 
    # Do some work in process 2 
    sleep 1 
    puts "Hello 2" 
    } 
} 

# Wait for the child processes to finish 
Process.wait 

Korzystanie fork podzieli przetwarzanie między rdzeniami procesora, więc jeśli można żyć bez wątków następnie oddzielne procesy są jednym ze sposobów, aby to zrobić.