Latest web development tutorials

rubino Multithreading

Ogni programma in esecuzione sul sistema è un processo. Ogni processo contiene uno o più thread.

Un thread è un unico flusso di controllo programma sequenziale, contemporaneamente eseguire più thread in un unico programma di fare cose diverse, chiamate multi-threading.

Ruby, ci possono essere creati da più di classe filetti filetto, fili di Ruby sono un peso leggero, può essere un modo efficace per implementare il codice parallelo.


La creazione di un filo di Ruby

Per iniziare una nuova discussione, si può chiamare Thread.new:

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

Esempi

L'esempio seguente mostra come utilizzare il multithreading in programma in 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}"

Il codice precedente viene eseguito come risultato di:

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

Life Cycle Discussione

1, creare un thread può usare Thread.new, è anche possibile utilizzare la stessa sintassi Thread.start o Thread.fork tre modi per creare un filo.

2, creare un filo senza avviare, il filo verrà eseguito automaticamente.

3, classe Thread definisce i metodi per manipolare thread. Discussione di blocchi di codice esecuzione Thread.new.

4, il blocco di filettatura è il valore dell'ultima istruzione nel filo, il filo può essere richiamato da un metodo, se il filo è terminato, restituisce il valore del filo, o non restituisce un valore fino a quando il filo è terminato.

5, metodo Thread.current restituisce un oggetto per la rappresentazione thread corrente. Metodo Thread.main restituisce il thread principale.

6, il metodo viene eseguito da fili Thread.join, questo metodo si sospende il thread principale finché il thread corrente è terminata.


Stato Discussione

Discussione ha cinque stati:

Stato Discussione Valore di ritorno
eseguibile corsa
addormentato addormentato
smettere interruzione
terminazione normale falso
anomala si verifica zero

Fili e aberranti

Quando si verifica un'eccezione filo, e nessun salvataggio è stato catturato, il filo sarebbe normalmente chiuso senza preavviso. Tuttavia, se gli altri filetti filetto # uniscono perché il rapporto è stato in attesa di questa discussione, poi i thread in attesa saranno inoltre sollevato la stessa eccezione.

begin
  t = Thread.new do
    Thread.pass    # 主线程确实在等join
    raise "unhandled exception"
  end
  t.join
rescue
  p $!  # => "unhandled exception"
end

Utilizzare i seguenti tre metodi, è possibile ottenere l'interprete di interrompere l'operazione quando un thread viene terminato a causa di un'eccezione.

  • script di avvio specifica opzione-d, e il funzionamento in modalità di debug.
  • Con Thread.abort_on_exception impostare il flag.
  • Utilizzare Thread#abort_on_exception set filo specificato bandiera.

Quando si utilizza uno dei tre metodi sopra descritti, l'intero interprete verrà interrotta.

t = Thread.new { ... }
t.abort_on_exception = true

sincronizzazione dei thread

In Ruby, fornisce tre modo sincronizzato, vale a dire:

1. classe Mutex implementa la sincronizzazione dei thread

2. classe di coda di trasferimento dati sulla regolamentazione implementare sincronizzazione dei thread

controllo di sincronizzazione 3. Utilizzare ConditionVariable

Con Mutex classe implementa la sincronizzazione dei thread

Per classe Mutex implementa il controllo sincronizzazione dei thread, se anche è necessario un programma di clock variabile in più thread, è possibile utilizzare il blocco per bloccare la parte variabile. Il codice è il seguente:

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

Il codice precedente viene eseguito come risultato di:

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

Oltre a utilizzare locked variabile, è possibile utilizzare anche try_lock variabile bloccata, è anche possibile utilizzare Mutex.synchronize sincronizzare l'accesso a una particolare variabile.

il trasferimento dei dati sulla regolamentazione della classe Queue implementa la sincronizzazione dei thread

classe Queue che rappresenta una coda di supporto del filo, la coda può essere sincronizzato alla fine della visita. Diversi thread possono utilizzare una classe unificata, ma non preoccuparsi se i dati possono essere sincronizzati in questa coda, oltre a limitare l'uso di SizedQueue lunghezza della coda di classe

Classe SizedQueue può essere molto conveniente per aiutarci a sviluppare applicazioni filettate da sincronizzare, problemi di sincronizzazione dovrebbero essere aggiunti alla lunga coda, non si preoccupano le discussioni.

produttori classici e consumatori:

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

output del programma:

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

Variabili discussione

Discussione può avere la sua variabile privata, un filo variabile privata filo scrittura quando viene creato il thread. Può essere utilizzato nell'ambito della filettatura, ma il filo non può essere condivisa esternamente.

Ma a volte, le variabili locali filo non hanno bisogno di un altro thread o il thread principale per accedere come fare? rubino permette loro di creare un filo è fornito dal nome della variabile, il filo è visto come stile simile tabella di hash hash. Con [] = scritto da [] la lettura dei dati. Guardiamo il seguente codice:

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

Il codice di cui sopra viene eseguito in uscita è:

8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10

I principali thread attende per l'esecuzione thread figlio è completata, e quindi uscite ogni valore. .


priorità Discussione

la priorità del thread è il fattore principale che interessa la programmazione thread. Altri fattori includono la lunghezza del tempo per eseguire CPU-thread pianificazione dei pacchetti e così via.

È possibile utilizzare Thread.priority ottenuto la priorità di un thread e utilizzare Thread.priority = metodo per regolare la priorità del thread.

default priorità di un thread a 0. Più veloce esecuzione di priorità più alta.

Un thread può accedere a tutti i dati nell'ambito di loro, ma se ci sono altri thread devono accedere ai dati in un thread dovrebbe essere come fare? classe thread fornisce i dati di thread accedono a vicenda, si può semplicemente mettere un filo come una tabella di hash, può essere utilizzato in qualsiasi thread [] = dati scrivere, usare [] la lettura dei dati.

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"]}" }

Possiamo vedere, il filo come una tabella hash, usare [] o [] = metodo, abbiamo raggiunto la condivisione dei dati tra i thread.


mutex Discussione

Mutex (Reciproca Esclusione = mutex) è un metodo per la programmazione multi-threaded, un meccanismo per evitare che due thread simultaneamente per le stesse risorse pubbliche (come le variabili globali) in lettura e scrittura.

Esempi di non utilizzo 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}"

Eseguire l'uscita precedente esempio è il seguente:

count1 :  9712487
count2 :  12501239
difference : 0

Esempio di 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}"

Eseguire l'uscita precedente esempio è il seguente:

count1 :  1336406
count2 :  1336406
difference : 0

punto morto

Più di due unità operative, entrambe le parti sono in attesa per l'altro per interrompere l'esecuzione, per ottenere le risorse di sistema, ma non una uscita anticipata partito, questa situazione si chiama stallo.

Ad esempio, un processo richiede p1 up display, mentre è necessario utilizzare la stampante, e la stampante è occupata dal p2 processo, p2 deve utilizzare il monitor, formando così una situazione di stallo.

Quando usiamo Mutex oggetto ha bisogno di attenzione filo stallo.

Esempi

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

L'output sopra esempio è:

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!

metodo di classe Discussione

Discussione (thread) metodo di classe completo come segue:

No. metodo Descrizione
1 Thread.abort_on_exception
Se è vero, una volta che termina un thread a causa di un'eccezione, l'intero interprete verrà interrotta. Il valore predefinito è falso, cioè, in circostanze normali, se si verifica un'eccezione filo e l'eccezione non è thread # uniscono e altri rilevato, il filo sarà terminato senza preavviso.
2 Thread.abort_on_exception =
Se impostato atrue,una volta che termina un thread a causa di un'eccezione, l'intero interprete verrà interrotta. Restituisce nuovo stato
3 Thread.critical
Restituisce un valore booleano.
4 Thread.critical =
Quando il valore è vero, il filo non verrà commutata. Se il thread corrente per appendere (stop) o il segnale di intervento (segnale), il suo valore sarà cambiato automaticamente su false.
5 Thread.current
Restituisce il filo conduttore di corrente (il thread corrente).
6 Thread.exit
Termina il thread corrente. Restituisce il thread corrente. Se il thread corrente è l'unico filo, con l'uscita (0) per terminare il suo funzionamento.
7 Thread.fork {block}
Come con Thread.new generare discussioni.
8 Thread.kill (aThread)
Terminare il filo conduttore.
9 Thread.list
Restituisce un array di filo dal vivo è in funzione o stato sospeso.
10 Thread.main
Ritorno al thread principale.
11 Thread.new ([arg] *) { | args | block}
Generare filo e avviare l'esecuzione. Il numero verrà passato intatta al blocco. Questo può iniziare un thread allo stesso tempo, il valore verrà passato alle variabili locali inerenti al filo.
12 Thread.pass
Il diritto di eseguire altri thread. Non cambia lo stato dei thread in esecuzione, ma consegnerà il controllo di altri thread può essere eseguito (Explicit programmazione dei thread).
13 Thread.start ([args] *) { | args | block}
Generare filo e avviare l'esecuzione. Il numero verrà passato intatta al blocco. Questo può iniziare un thread allo stesso tempo, il valore verrà passato alle variabili locali inerenti al filo.
14 Thread.stop
Il thread corrente viene sospesa fino a quando gli altri thread metodo run di nuovo svegliano il filo.

metodo di istanza Discussione

L'esempio seguente chiama il metodo di istanza filo unirsi:

#!/usr/bin/ruby

thr = Thread.new do   # 实例化
   puts "In second thread"
   raise "Raise exception"
end
thr.join   # 调用实例化方法 join

Ecco un elenco completo di esempi del metodo:

No. metodo Descrizione
1 thr [nome]
Rimuovere il filo del nome corrispondente ai dati inerenti. nome può essere una stringa o un simbolo. Se il nome non corrisponde ai dati, restituisce nil.
2 thr [nome] =
Impostare il valore del nome filo nei corrispondenti dati caratteristici, nome può essere una stringa o un simbolo. Se impostato a zero, rimuove i dati corrispondenti a questo thread.
3 thr.abort_on_exception
Restituisce un valore booleano.
4 thr.abort_on_exception =
Se il suo valore è vero, allora una volta che termina un thread a causa di un'eccezione, l'intero interprete verrà interrotta.
5 thr.alive?
Se il filo è "live", restituisce vero.
6 thr.exit
Terminare il filo conduttore. Restituisce sé.
7 thr.join
Sospende il thread corrente fino a quando la corsa di auto fino a quando il filo termina. Se l'auto a causa di chiusura anomala, il thread corrente attiverà la stessa eccezione.
8 thr.key?
Se il nome corrispondente ai dati inerenti le discussioni è stato definito, quindi restituisce true
9 thr.kill
Thread.exit simile.
10 thr.priority
Restituisce la priorità del thread. La priorità predefinita è 0. Maggiore è il valore, maggiore è la priorità.
11 thr.priority =
Impostare la priorità del thread. È inoltre possibile impostare a negativo.
12 thr.raise (anException)
All'interno di questa discussione con la forza gettato.
13 thr.run
Riavviare attesa filo (stop). La differenza è che con la sveglia condurrà filo di commutazione immediatamente. Se si utilizza questo metodo per elaborare i morti verrà sollevata un'eccezione ThreadError.
14 thr.safe_level
Restituisce il livello di sicurezza di sé. Safe_level thread corrente $ SAFE stessa.
15 thr.status
Utilizzando la stringa "run", "sonno" o "abortire" per indicare lo stato del filo dal vivo se un thread viene terminato normalmente, quindi restituisce false. Ruoyin anomala, poi ritorna a zero.
16 thr.stop?
Se il thread viene terminato stato (morto) o sospendere (arresto), il ritorno vero.
17 thr.value
Attendere il filo sé termina (equivalente ad unirsi), restituisce il valore del blocco del filo se i fili conduttori si verificano durante anormale, l'eccezione viene nuovamente sollevata.
18 thr.wakeup
Lo stato è sospeso (stop) di filo allo stato pronto (pista), se il metodo viene eseguito sul thread morti solleverà ThreadError eccezione.