Najlepszy samouczek Ruby Wielowątkowość W 2024 r. W tym samouczku możesz dowiedzieć się Tworzenie wątku Ruby,Cykl życia Wątek,Stan wątku,Nici i nienormalna,Synchronizacja wątek,Zmienne wątku,priorytet wątku,mutex wątek,impas,metoda klasy Thread,Temat wystąpienia metoda,
Każdy program uruchomiony w systemie jest procesem. Każdy proces zawiera jeden lub większą liczbę wątków.
Wątek jest pojedynczy sekwencyjny przepływ sterowania programem, jednocześnie uruchamiać wiele wątków w jednym programie robić różne rzeczy, zwane wielowątkowości.
Ruby, możemy być tworzone poprzez wielokrotne klasy nici wątku, Ruby gwinty są lekkie, może być skutecznym sposobem wdrożenia kodu równoległego.
Aby rozpocząć nowy wątek, można po prostu zadzwonić Thread.new:
# 线程 #1 代码部分 Thread.new { # 线程 #2 执行代码 } # 线程 #1 执行代码
Poniższy przykład pokazuje, jak używać wielowątkowość w programie Ruby:
#!/usr/bin/ruby def func1 i=0 while i<=2 puts "func1 at: #{Time.now}" sleep(2) i=i+1 end end def func2 j=0 while j<=2 puts "func2 at: #{Time.now}" sleep(1) j=j+1 end end puts "Started At #{Time.now}" t1=Thread.new{func1()} t2=Thread.new{func2()} t1.join t2.join puts "End at #{Time.now}"
Powyższy kod jest wykonywany w wyniku:
Started At Wed May 14 08:21:54 -0700 2014 func1 at: Wed May 14 08:21:54 -0700 2014 func2 at: Wed May 14 08:21:54 -0700 2014 func2 at: Wed May 14 08:21:55 -0700 2014 func1 at: Wed May 14 08:21:56 -0700 2014 func2 at: Wed May 14 08:21:56 -0700 2014 func1 at: Wed May 14 08:21:58 -0700 2014 End at Wed May 14 08:22:00 -0700 2014
1, stworzyć wątek może wykorzystać Thread.new, można również korzystać z tego samego Thread.start składni lub Thread.fork trzy sposoby tworzenia wątku.
2, utworzyć wątku bez uruchamiania, wątek zostanie wykonana automatycznie.
3, klasa Thread definiuje metody manipulowania wątku. Wątek wykonywanie kodu Thread.new bloków.
4, blok wątek jest wartość ostatniej wypowiedzi w wątku, wątek może być wywołany przez sposób, jeśli wątek jest zakończona, to zwraca wartość wątku, albo nie zwraca wartości dopóki wątek jest skończony.
5, Sposób Thread.current zwraca obiekt dla aktualnej reprezentacji gwintu. Metoda Thread.main zwraca główny wątek.
6, przy czym sposób przeprowadza się Thread.Join nici, sposób ten zawiesza główny gwint aż prąd gwint jest zakończone.
Wątek ma pięć stanów:
Stan wątku | Wartość zwracana |
---|---|
wykonywalny | bieg |
spanie | spanie |
porzucić | przerywanie |
normalne zakończenie | fałszywy |
Nienormalne zakończenie nastąpi | zero |
Kiedy pojawia się wyjątek wątku i nie ratownicza została schwytana, wątek normalnie zostać rozwiązana bez ostrzeżenia. Jednakże, jeśli # inne wątki wątku dołączyć ponieważ relacja została czeka na tego wątku, to nici czekają również zostaną podniesione ten sam wyjątek.
begin t = Thread.new do Thread.pass # 主线程确实在等join raise "unhandled exception" end t.join rescue p $! # => "unhandled exception" end
Za pomocą trzech następujących metod, można uzyskać pomoc tłumacza, aby przerwać operację, gdy wątek kończy się z powodu wyjątku.
Thread.abort_on_exception
ustawić flagę. Thread#abort_on_exception
określony zestaw nici flagę. Podczas korzystania z jednej z trzech metod opisanych powyżej, cały interpreter zostanie przerwane.
t = Thread.new { pl. } t.abort_on_exception = true
W Ruby, posiada trzy zsynchronizowany sposób, a mianowicie:
1. klasy Mutex realizuje synchronizacji wątku
2. Regulacji transfer danych klasy Queue wdrożenia synchronizacji wątku
Regulacja synchronizacji 3. Zastosowanie ConditionVariable
Przez klasy mutex realizuje kontrolę synchronizacji wątków, jeśli trzeba także program zmiennej zegar w wielu wątków, można korzystać z blokady, aby zablokować zmienną część. Kod jest w następujący sposób:
#!/usr/bin/ruby require "thread" puts "Synchronize Thread" @num=200 @mutex=Mutex.new def buyTicket(num) @mutex.lock if @num>=num @num=@num-num puts "you have successfully bought #{num} tickets" else puts "sorry,no enough tickets" end @mutex.unlock end ticket1=Thread.new 10 do 10.times do |value| ticketNum=15 buyTicket(ticketNum) sleep 0.01 end end ticket2=Thread.new 10 do 10.times do |value| ticketNum=20 buyTicket(ticketNum) sleep 0.01 end end sleep 1 ticket1.join ticket2.join
Powyższy kod jest wykonywany w wyniku:
Synchronize Thread you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets
Oprócz korzystania z blokady zablokowane zmienną, można również użyć try_lock zmienną zablokowana, można również użyć Mutex.synchronize synchronizowania dostępu do określonej zmiennej.
Klasa kolejkę przedstawia kolejkę pomocy gwintu, kolejki może być synchronizowany z końcem wizyty. Różne wątki mogą wykorzystywać jednolitą klasę, ale nie martw się o to, czy dane mogą być synchronizowane w tej kolejce, oprócz ograniczenia użycia SizedQueue długości kolejki klasy
Klasa SizedQueue może być bardzo wygodne, aby pomóc nam rozwijać wielowątkowych aplikacji do synchronizacji, problemy z synchronizacją należy dodać do długiej kolejce, nie dbam o wątkach.
Klasyczne producentów i konsumentów:
#!/usr/bin/ruby require "thread" puts "SizedQuee Test" queue = Queue.new producer = Thread.new do 10.times do |i| sleep rand(i) # 让线程睡眠一段时间 queue << i puts "#{i} produced" end end consumer = Thread.new do 10.times do |i| value = queue.pop sleep rand(i/2) puts "consumed #{value}" end end consumer.join
Wyjście programu:
SizedQuee Test 0 produced 1 produced consumed 0 2 produced consumed 1 consumed 2 3 produced consumed 34 produced consumed 4 5 produced consumed 5 6 produced consumed 6 7 produced consumed 7 8 produced 9 produced consumed 8 consumed 9
Wątek może mieć swój prywatny zmienna, zmienna wątek prywatny wątek pisania gdy wątek jest tworzony. Może być stosowany w zakresie od gwintu, ale nić nie mogą być dzielone na zewnątrz.
Ale czasami, gwint zmienne lokalne nie potrzebujemy innego wątku lub główny wątek dostępu jak to zrobić? Ruby pozwala im stworzyć wątek jest nazwą zmiennej, wątek jest postrzegany jako podobny styl tabeli hash hash. Przez [] = napisany przez [] odczytu danych. Patrzymy na następujący kod:
#!/usr/bin/ruby count = 0 arr = [] 10.times do |i| arr[i] = Thread.new { sleep(rand(0)/10.0) Thread.current["mycount"] = count count += 1 } end arr.each {|t| t.join; print t["mycount"], ", " } puts "count = #{count}"
Powyższy kod jest uruchamiany wyjście jest:
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10
Głównymi wątek czeka na wykonanie gwintu dziecko jest zakończona, a następnie wyprowadza każdą wartość. ,
Priorytet wątku jest głównym czynnikiem wpływającym na harmonogram gwintu. Inne czynniki obejmują czas wykonywania szeregowania pakietów procesora gwintu i tak dalej.
Można użyć Thread.priority uzyskuje priorytet wątku i użyć metody Thread.priority = aby ustawić priorytet wątku.
priorytetowe domyślnie wątku jest na 0. Szybsza realizacja wyższym priorytecie.
Wątek może uzyskać dostęp do wszystkich danych w ramach ich własnych, ale jeśli istnieją inne wątki potrzebują dostępu do danych w wątku powinien być, jak to zrobić? Klasa Temat zapewnia dostęp do danych gwint siebie, można po prostu umieścić wątku w tabeli mieszania, mogą być wykorzystywane w żadnym wątku [] = Zapis danych, użyj [] odczytu danych.
athr = Thread.new { Thread.current["name"] = "Thread A"; Thread.stop } bthr = Thread.new { Thread.current["name"] = "Thread B"; Thread.stop } cthr = Thread.new { Thread.current["name"] = "Thread C"; Thread.stop } Thread.list.each {|x| puts "#{x.inspect}: #{x["name"]}" }
Widzimy, nić jako tabeli mieszania użyj [] i [] = metoda osiągnęliśmy wymiany danych pomiędzy wątkami.
Mutex (mutal Wykluczenie = mutex) to metoda programowania wielowątkowego, mechanizm zapobiegania dwa wątki jednocześnie z tych samych środków publicznych (takich jak zmienne globalne) czytać i pisać.
#!/usr/bin/ruby require 'thread' count1 = count2 = 0 difference = 0 counter = Thread.new do loop do count1 += 1 count2 += 1 end end spy = Thread.new do loop do difference += (count1 - count2).abs end end sleep 1 puts "count1 : #{count1}" puts "count2 : #{count2}" puts "difference : #{difference}"
Uruchom wyjście Powyższy przykład to:
count1 : 9712487 count2 : 12501239 difference : 0
#!/usr/bin/ruby require 'thread' mutex = Mutex.new count1 = count2 = 0 difference = 0 counter = Thread.new do loop do mutex.synchronize do count1 += 1 count2 += 1 end end end spy = Thread.new do loop do mutex.synchronize do difference += (count1 - count2).abs end end end sleep 1 mutex.lock puts "count1 : #{count1}" puts "count2 : #{count2}" puts "difference : #{difference}"
Uruchom wyjście Powyższy przykład to:
count1 : 1336406 count2 : 1336406 difference : 0
Więcej niż dwóch jednostek operacyjnych, obie strony czekają na drugi, aby zatrzymać uruchomiony, aby uzyskać zasobów systemowych, ale nie jest to wczesny zjazd partii, taka sytuacja nazywa się impasu.
Na przykład, p1 proces odbywa się wyświetlacz, natomiast trzeba korzystać z drukarki, a drukarka jest zajęta przez p2 procesowego, p2 musi także korzystać z monitora, tworząc impas.
Gdy używamy Mutex obiekt potrzebuje gwintu uwagę impasu.
#!/usr/bin/ruby require 'thread' mutex = Mutex.new cv = ConditionVariable.new a = Thread.new { mutex.synchronize { puts "A: I have critical section, but will wait for cv" cv.wait(mutex) puts "A: I have critical section again! I rule!" } } puts "(Later, back at the ranchpl.)" b = Thread.new { mutex.synchronize { puts "B: Now I am critical, but am done with cv" cv.signal puts "B: I am still critical, finishing up" } } a.join b.join
Powyższy przykład wyjście jest:
A: I have critical section, but will wait for cv (Later, back at the ranchpl.) B: Now I am critical, but am done with cv B: I am still critical, finishing up A: I have critical section again! I rule!
Kompletna wątek (thread) Sposób następująco klasy:
Nie. | metoda Opis |
---|---|
1 | Thread.abort_on_exception Jeśli prawdą jest, gdy wątek kończy się z powodu wyjątku, cały interpreter zostanie przerwane. Wartością domyślną jest false, to znaczy, w normalnych okolicznościach, jeżeli wystąpi wyjątek wątku i wyjątek nie jest wątek # dołączyć i innych wykrytych, wątek zostanie rozwiązana bez ostrzeżenia. |
2 | Thread.abort_on_exception = Jeśli ma wartośćtrue,gdy wątek kończy się z powodu wyjątku, cały interpreter zostanie przerwane. Zwraca nowy stan |
3 | Thread.critical Zwraca wartość logiczną. |
4 | Thread.critical = Gdy wartość jest prawdą, nitka nie zostanie włączony. Jeśli bieżący wątek do powieszenia (STOP) lub sygnał (sygnał) interwencji, jego wartość zostanie automatycznie zmieniony na false. |
5 | Thread.current Zwraca bieżącą wątkiem (bieżącego wątku). |
6 | Thread.exit To kończy bieżący wątek. Zwraca bieżący wątek. Jeśli obecna jest tylko nić wątku przy użyciu wyjścia (0), aby zakończyć swoje działanie. |
7 | Thread.fork {block} Podobnie jak w przypadku Thread.new generować wątki. |
8 | Thread.kill (aThread) Kończy bieg gwintu. |
9 | Thread.list Zwraca tablicę wątku żywo działa lub zawiesza stan. |
10 | Thread.main Powrót do głównego wątku. |
11 | Thread.new ([arg] *) { | args | block} Generowanie wątek i rozpocząć wykonywanie. Liczba są przekazywane w stanie nienaruszonym do bloku. To może uruchomić wątku w tym samym czasie, to wartość ta jest przekazywana do lokalnego zmiennych związanych w wątku. |
12 | Thread.pass Prawo do uruchamiania innych wątków. To nie zmienia stan uruchomionych wątków, ale przekaże kontrolę innych wątków można uruchomić (Explicit harmonogram wątku). |
13 | Thread.start ([args] *) { | args | block} Generowanie wątek i rozpocząć wykonywanie. Liczba są przekazywane w stanie nienaruszonym do bloku. To może uruchomić wątku w tym samym czasie, to wartość ta jest przekazywana do lokalnego zmiennych związanych w wątku. |
14 | Thread.stop Bieżący wątek jest zawieszona aż inne wątki prowadzone metodą znów obudzić wątku. |
Poniższy przykład wywołuje metodę instancji wątku dołączyć:
#!/usr/bin/ruby thr = Thread.new do # 实例化 puts "In second thread" raise "Raise exception" end thr.join # 调用实例化方法 join
Powyżej znajduje się pełna lista przykładów metody:
Nie. | metoda Opis |
---|---|
1 | Thr [nazwa] Usunięcie nici nazwy odpowiedniego do danych właściwych. Nazwa może mieć ciąg lub symbol. Jeśli nazwa nie jest zgodne z danymi, zwraca nil. |
2 | Thr [nazwa] = Ustaw wartość nazwa wątku w odpowiednich danych charakterystycznych, nazwa może być ciągiem znaków lub symboli. Jeśli jest ustawiony na zero, usuwa odpowiednie dane w tym wątku. |
3 | thr.abort_on_exception Zwraca wartość logiczną. |
4 | thr.abort_on_exception = Jeśli jego wartość jest prawdziwa, a następnie raz w gwint kończy się z powodu wyjątku, cały interpreter zostanie przerwane. |
5 | thr.alive? Jeśli wątek jest "na żywo", to zwraca true. |
6 | thr.exit Kończy bieg gwintu. Zwraca siebie. |
7 | thr.join Zawiesza bieżącego wątku, dopóki metę siebie aż wątek kończy. Jeśli self powodu nieprawidłowego wypowiedzenia bieżący wątek wywoła ten sam wyjątek. |
8 | thr.key? Jeśli nazwa odpowiadająca danych związanych zostało zdefiniowane nici, a następnie zwraca wartość true |
9 | thr.kill PodobnyThread.exit. |
10 | thr.priority Zwraca priorytet wątku. Domyślnym priorytetem jest 0. Im większa wartość, tym wyższy priorytet. |
11 | thr.priority = Ustawianie priorytetu wątku. Można również ustawić go na negatywną. |
12 | thr.raise (anException) W tym wątku siłą wyrzucony. |
13 | thr.run Uruchom ponownie w toku (stop) wątku. Różnica polega na tym, że przy wznawianiu przeprowadzi wątek przełączania natychmiast. W przypadku korzystania z tej metody przetwarzania martwych zostanie podniesiona wyjątek ThreadError. |
14 | thr.safe_level Zwraca poziom zabezpieczeń siebie. Safe_level bieżący wątek $ SAFE samo. |
15 | thr.status Korzystanie ciąg "run", "uśpienia" lub "Przerwanie", aby wskazać status wątku na żywo, jeśli wątek jest zakończony normalnie, to zwraca false. Ruoyin nieprawidłowym zakończeniu, wówczas zwraca nil. |
16 | thr.stop? Jeśli wątek jest zakończony stan (DEAD) lub wstrzymania (przystanek), powrót prawdziwego. |
17 | thr.value Poczekaj, aż zakończy własny wątek (odpowiednik join), zwraca wartość bloku gwintu czy uruchomione wątki wystąpić podczas nienormalne, wyjątek zostaną wskrzeszeni. |
18 | thr.wakeup Stan jest zawieszony (STOP) nici do gotowej państwowej (RUN), czy metoda jest wykonywana na martwym wątku podniesie ThreadError wyjątek. |