Ruby-Multithreading
Jedes Programm auf dem System ausgeführt ist ein Prozess. Jeder Prozeß enthält ein oder mehrere Threads.
Ein Thread ist ein einzelner sequentieller Programmablaufsteuerung, gleichzeitig mehrere Threads in einem einzigen Programm verschiedene Dinge tun, die so genannte Multi-Threading laufen.
Rubin, können wir von mehreren Threads Thread-Klasse erstellt werden, sind Ruby-Threads ein leichtes, kann es eine effiziente Möglichkeit, parallel Code zu implementieren.
Erstellen eines Ruby-Thread
Um einen neuen Thread starten, können Sie einfach Thread.new nennen:
# 线程 #1 代码部分 Thread.new { # 线程 #2 执行代码 } # 线程 #1 执行代码
Beispiele
Das folgende Beispiel zeigt, wie Multithreading zu verwenden, in Ruby-Programm:
#!/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}"
Der obige Code wird als Ergebnis der Ausführung:
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
Thema Life Cycle
1, einen Thread erstellen Thread.new verwenden, können Sie auch die gleiche Syntax Thread.start oder Thread.fork verwenden drei Möglichkeiten, um einen Thread zu erstellen.
2, einen Thread zu erstellen, ohne starten, dann wird der Faden automatisch ausgeführt werden.
3, Thread-Klasse definiert Methoden Thread zu manipulieren. Thread der Ausführung Thread.new Codeblöcke.
4 ist der Gewindesatz ist der Wert der letzten Anweisung in dem Gewinde kann der Faden durch ein Verfahren aufgerufen werden, wenn der Thread beendet ist, wird der Wert des Fadens zurückkehrt oder zurückzukehren keinen Wert, bis der Thread beendet ist.
5, kehrt Thread.current Methode ein Objekt für den aktuellen Thread-Darstellung. Thread.main Methode gibt den Haupt-Thread.
6, wobei das Verfahren durch Thread.Join Threads ausgeführt wird, wird diese Methode unterbrechen wird, um den Haupt-Thread, bis der aktuelle Thread beendet.
Thread-Zustand
Thema hat fünf Staaten:
Thread-Zustand | Rückgabewert |
---|---|
ausführbar | Lauf |
schlafend | schlafend |
verlassen | Abbruchs |
Normale Beendigung | falsch |
Abnormale Beendigung auftritt | Null |
Themen und anomale
Wenn ein Thread Ausnahme auftritt, und keine Rettung gefangen genommen wurde, würde der Faden normalerweise ohne Vorwarnung beendet werden. Allerdings, wenn andere Threads Thread # beitreten, weil die Beziehung für diesen Thread gewartet hat, dann werden die wartenden Threads wird auch die gleiche Ausnahme ausgelöst werden.
begin t = Thread.new do Thread.pass # 主线程确实在等join raise "unhandled exception" end t.join rescue p $! # => "unhandled exception" end
Verwenden Sie die folgenden drei Methoden können Sie den Interpreter erhalten, um den Betrieb zu unterbrechen, wenn ein Thread auf eine Ausnahme aufgrund beendet.
- Startup - Skript gibt Option-d und Debugging - Modus - Betrieb.
- Mit
Thread.abort_on_exception
das Kennzeichen. - Verwenden Sie
Thread#abort_on_exception
angegebenen Thread - Set - Flag.
Wenn eines von drei Verfahren unter Verwendung der oben beschriebenen, wird das gesamte Interpreter abgebrochen werden.
t = Thread.new { de. } t.abort_on_exception = true
Themen-Synchronisation
In Ruby bietet drei aufeinander abgestimmten Weise, nämlich:
1. Mutex-Klasse implementiert Threadsynchronisierung
2. Regulatorische Datenübertragung Queue-Klasse implementieren Thread-Synchronisation
3. Verwenden Sie Conditionsynchronisationssteuerung
Durch Mutex implementiert Klasse Thread-Synchronisation
Durch die Mutex-Klasse implementiert die Thread-Synchronisation Kontrolle, wenn Sie auch eine Programmvariable Uhr in mehreren Threads benötigen, können Sie die Sperre zu verwenden den variablen Teil zu sperren. Code ist wie folgt:
#!/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
Der obige Code wird als Ergebnis der Ausführung:
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
Neben der Verwendung von Schloss verriegelt Variablen können Sie auch try_lock verriegelte Variable verwenden, können Sie auch Mutex.synchronize Zugriff auf eine bestimmte Variable synchronisieren.
Regulatorische Datenübertragung der Queue-Klasse implementiert Threadsynchronisierung
Queue-Klasse, die einen Thread Support-Warteschlange darstellt, kann die Warteschlange bis zum Ende des Besuchs synchronisiert werden. Verschiedene Threads können eine einheitliche Klasse zu verwenden, aber keine Sorge darüber, ob die Daten in dieser Warteschlange synchronisiert werden, zusätzlich die Verwendung von SizedQueue Klasse Warteschlangenlänge zu begrenzen,
SizedQueue Klasse kann sehr praktisch sein, um uns Threaded-Anwendungen entwickeln helfen zu synchronisieren, sollten Synchronisationsprobleme zu der langen Warteschlange hinzugefügt werden, Sie kümmern sich nicht um Threads.
Klassische Produzenten und Konsumenten:
#!/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
Programmausgabe:
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
Thread-Variablen
Thread kann seine private Variable, einen Thread private Variable Schreib Thread, wenn der Thread erstellt wird. Es kann im Rahmen des Gewindes verwendet werden, aber der Faden kann nicht extern geteilt werden.
Aber manchmal sind die lokalen Thread-Variablen brauchen keinen neuen Thread oder den Haupt-Thread zuzugreifen, wie zu tun? Rubin ermöglicht es ihnen, einen Thread zu erstellen, indem Sie den Variablennamen zur Verfügung gestellt wird, wird der Faden ähnlichen Stil Hash-Hash-Tabelle zu sehen, wie. Mit dem [] = geschrieben von [] Daten lesen. Wir schauen auf den folgenden Code:
#!/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}"
Der obige Code ausgeführt wird, ausgegeben wird:
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10
Die Haupt-Thread wartet auf das Kind Thread-Ausführung ist, abgeschlossen und gibt dann jeden Wert. .
Thread-Priorität
Thema Priorität ist der wesentliche Faktor der Thread-Scheduling. Andere Faktoren umfassen die Länge der Zeit, CPU-thread Paket-Scheduling durchzuführen, und so weiter.
Sie können Thread.Priority verwenden, um ein Thread Priorität erhalten und verwenden Thread.Priority = Methode, um die Thread-Priorität einzustellen.
Eine Priorität des Threads automatisch auf 0. Schnellere Ausführung mit höherer Priorität.
Ein Thread kann auf alle Daten zugreifen im Rahmen der eigenen, aber wenn es andere Threads Daten in einem Thread zugreifen müssen sein sollte, wie es zu tun? Thread-Klasse bietet Thread-Daten aufeinander zugreifen, können Sie einfach einen Thread als Hash-Tabelle setzen kann, kann in alle gängigen Gewinde [] = Write-Daten verwendet werden, verwenden Sie [] Lesen von Daten.
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"]}" }
Wir können sehen, den Faden als Hash-Tabelle, verwenden Sie [] und [] = Methode erzielten wir Daten zwischen Threads zu teilen.
Thema Mutex
Mutex (Mutal Exclusion = mutex) ist ein Verfahren zur Multi-Threaded-Programmierung, ein Mechanismus zwei Threads für die gleichen öffentlichen Ressourcen (wie globale Variablen) lesen und schreiben gleichzeitig zu verhindern.
Beispiele für nicht-use 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}"
Führen Sie das obige Beispiel Ausgabe lautet:
count1 : 9712487 count2 : 12501239 difference : 0
Beispiel für 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}"
Führen Sie das obige Beispiel Ausgabe lautet:
count1 : 1336406 count2 : 1336406 difference : 0
Deadlock
Mehr als zwei Betriebseinheiten sind beide Seiten warten auf die andere laufen zu stoppen, die Systemressourcen zu erhalten, aber nicht eine Partei ein vorzeitiges Ausscheiden, diese Situation wird Deadlock genannt.
Zum Beispiel kann ein Prozess p1 Display einnimmt, während Sie den Drucker verwenden müssen, und der Drucker durch den Prozess p2 belegt ist, p2 muss auch den Monitor verwenden, wodurch eine Sackgasse bilden.
Wenn wir Mutex braucht Aufmerksamkeit Thread-Deadlock-Objekt verwenden.
Beispiele
#!/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 ranchde.)" 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
Das obige Beispiel Ausgabe lautet:
A: I have critical section, but will wait for cv (Later, back at the ranchde.) 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!
Thread-Klasse-Methode
Vollständige Thread (Thread) Klassenmethode wie folgt:
Nein. | Methode Beschreibung |
---|---|
1 | Thread.abort_on_exception Wenn es wahr ist, wenn ein Thread aufgrund einer Ausnahme beendet wird, wird der gesamte Dolmetscher unterbrochen. Der Standardwert ist falsch, das heißt, unter normalen Umständen, wenn ein Thread Ausnahme auftritt und die Ausnahme nicht Thread # join und andere erkannt, wird der Faden ohne Warnung beendet werden. |
2 | Thread.abort_on_exception = Wenn auftrue gesetzt,einmal beendet ein Thread aufgrund einer Ausnahme, wird der gesamte Dolmetscher unterbrochen werden. Gibt neuen Staat |
3 | Thread.critical Gibt einen Booleschen Wert. |
4 | Thread.critical = Wenn der Wert true ist, wird der Faden umgeschaltet werden. Wenn der aktuelle Thread (Stopp) oder ein Signal (Signal) Intervention zu hängen, wird sein Wert automatisch auf false geändert werden. |
5 | Thread.current Gibt den aktuellen laufenden Faden (der aktuelle Thread). |
6 | Thread.exit Er beendet den aktuellen Thread. Gibt den aktuellen Thread. Wenn der aktuelle Thread der einzige Thread, den Ausgang mit (0) seinen Betrieb zu beenden. |
7 | Thread.fork {block} Wie bei Thread.new erzeugen Fäden. |
8 | Thread.kill (einThread) Beenden Sie den Faden läuft. |
9 | Thread.list Liefert ein Array von Live-Thread ausgeführt oder angehalten. |
10 | Thread.main Zurück zur Haupt-Thread. |
11 | Thread.new ([arg] *) { | args | block} Generieren Faden und beginnen Ausführung. Die Zahl wird intakt an den Block übergeben werden. Dieser einen Thread zur gleichen Zeit gestartet werden kann, wird der Wert der lokalen Variablen, die mit der Thread übergeben werden. |
12 | Thread.pass Die rechte anderen Threads ausgeführt werden. Es ist nicht der Zustand der laufenden Threads ändert, aber die Kontrolle über andere Threads übergeben kann (Explicit Thread-Scheduling) ausgeführt werden. |
13 | Thread.start ([args] *) { | args | block} Generieren Faden und beginnen Ausführung. Die Zahl wird intakt an den Block übergeben werden. Dieser einen Thread zur gleichen Zeit gestartet werden kann, wird der Wert der lokalen Variablen, die mit der Thread übergeben werden. |
14 | Thread.stop Der aktuelle Thread unterbrochen, bis die anderen Threads laufen Verfahren den Faden wieder aufwachen. |
Themen-Instanz-Methode
Das folgende Beispiel ruft der Thread-Instanz Verfahren beitreten:
#!/usr/bin/ruby thr = Thread.new do # 实例化 puts "In second thread" raise "Raise exception" end thr.join # 调用实例化方法 join
Dies ist die komplette Liste der Beispiele des Verfahrens:
Nein. | Methode Beschreibung |
---|---|
1 | thr [name] Entfernen Sie den Faden des Namens der inhärenten Daten entsprechen. Name kann eine Zeichenfolge oder ein Symbol sein. Wenn der Name auf die Daten nicht entspricht, kehrt sie gleich Null. |
2 | thr [name] = Stellen Sie den Thread-Namen-Wert in den entsprechenden Kenndaten können Name einen String oder ein Symbol sein. Wenn auf Null setzen, entfernt in diesem Thread die entsprechenden Daten. |
3 | thr.abort_on_exception Gibt einen Booleschen Wert. |
4 | thr.abort_on_exception = Wenn der Wert wahr ist, dann, wenn ein Thread beendet aufgrund einer Ausnahme, wird der gesamte Dolmetscher unterbrochen werden. |
5 | thr.alive? Wenn der Thread "live" ist, gibt es wahr. |
6 | thr.exit Beenden Sie den Faden läuft. Kosten selbst. |
7 | thr.join Unterbricht den aktuellen Thread, bis die Selbst laufen, bis der Thread beendet wird. Wenn der Selbst aufgrund abnormaler Beendigung der aktuelle Thread die gleiche Ausnahme auslösen. |
8 | thr.key? Wenn der Name der inhärenten Daten entsprechend definierten Fäden gegeben hat, dann gibt true zurück |
9 | thr.kill ÄhnlicheThread.exit. |
10 | thr.priority Gibt die Priorität des Threads. Die Standardpriorität 0. Je höher der Wert ist, desto höher ist die Priorität. |
11 | thr.priority = Einstellen der Thread-Priorität. Sie können sie auch auf negativ gesetzt. |
12 | thr.raise (anException) Innerhalb dieser Faden gewaltsam geworfen. |
13 | thr.run Starten Sie Pending (Stopp) Faden. Der Unterschied besteht darin, dass mit dem Wake-up-Thread-Umschalt sofort durchführen wird. Wenn mit dieser Methode die Toten zu verarbeiten ThreadError Ausnahme ausgelöst werden. |
14 | thr.safe_level Gibt Selbstsicherheitsstufe. Safe_level den aktuellen Thread $ SAFE gleich. |
15 | thr.status Unter Verwendung der Zeichenfolge "run", "Schlaf" oder "Abbrechen", um den Status der Live-Thread, um anzuzeigen, wenn ein Thread normal beendet wird, dann wird false zurückgegeben. Ruoyin abnormalen Beendigung, dann gibt es gleich Null. |
16 | thr.stop? Wenn der Faden Zustand (tot) beendet oder aussetzen (Stopp), die Rückkehr wahr. |
17 | thr.value Warten, bis der Selbst Thread beendet (äquivalent zu verbinden), um den Wert des Blocks des Threads zurück, wenn die laufenden Threads während abnormal auftreten, wird die Ausnahme wieder angehoben werden. |
18 | thr.wakeup Der Staat wird unterbrochen (Stop) Faden in den Bereitschaftszustand (run), wenn die Methode auf dem toten Thread ausgeführt wird, wird ThreadError Ausnahme ausgelöst. |