Latest web development tutorials

Ruby Wielowątkowość

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.


Tworzenie wątku Ruby

Aby rozpocząć nowy wątek, można po prostu zadzwonić Thread.new:

# 线程 #1 代码部分
Thread.new {
  # 线程 #2 执行代码
}
# 线程 #1 执行代码

Przykłady

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

Cykl życia Wątek

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.


Stan wątku

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

Nici i nienormalna

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.

  • Skrypt startowy określa opcję-d, oraz pracę w trybie debugowania.
  • Z Thread.abort_on_exception ustawić flagę.
  • Użyj 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 { ... }
t.abort_on_exception = true

Synchronizacja wątek

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 Mutex klasa implementuje synchronizacji wątku

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.

Regulacji transfer danych z klasy Queue implementuje synchronizacji wątku

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

Zmienne wątku

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

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 wątek

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ć.

Przykłady niestosowania Mutax

#!/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

Przykład Mutax

#!/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

impas

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.

Przykłady

#!/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 ranch...)"

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 ranch...)
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!

metoda klasy Thread

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.

Temat wystąpienia metoda

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.