Latest web development tutorials

rubí multithreading

Cada programa se ejecuta en el sistema es un proceso. Cada proceso contiene uno o más hilos.

Un hilo es un único flujo de control del programa secuencial, se ejecutan simultáneamente múltiples hilos en un solo programa hacen cosas diferentes, llamados multi-threading.

Ruby, que pueden ser creados por múltiples hilos de rosca de clase, roscas de Ruby son un peso ligero, puede ser una manera eficaz de poner en práctica código paralelo.


Creación de un hilo Rubí

Para iniciar un nuevo hilo, sólo puede llamar a Thread.new:

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

Ejemplos

El siguiente ejemplo muestra cómo utilizar múltiples hilos en el programa de 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}"

El código de seguridad se ejecuta como resultado de:

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

Ciclo de Vida del hilo

1, cree un hilo puede utilizar Thread.new, también puede utilizar la misma sintaxis o hilo.start Thread.fork tres maneras de crear un hilo.

2, crear un hilo sin empezar, el hilo se ejecutará automáticamente.

3, clase Thread define métodos para manipular hilo. Hilo de la ejecución de bloques de código Thread.new.

4, la secuencia de rosca es el valor de la última instrucción en el hilo, el hilo puede ser invocado por un método, si se acaba el hilo, se devuelve el valor de la rosca, o no devuelve un valor hasta que se termine el hilo.

5, el método Thread.current devuelve un objeto de la representación actual hilo. Thread.main método devuelve el hilo principal.

6, el método se lleva a cabo por medio de hilos Thread.Join, este método va a suspender el hilo principal hasta que se termine el hilo actual.


Estado hilo

Hilo tiene cinco estados:

Estado hilo Valor de retorno
ejecutable corrida
durmiente durmiente
dejar abortando
terminación normal falso
se produce una terminación anormal nulo

Hilos y aberrante

Cuando se produce una excepción de hilo, y ningún rescate fue capturado, el hilo normalmente se daría por terminado sin previo aviso. Sin embargo, si otros hilos de rosca # unen porque la relación ha estado esperando este hilo, a continuación, los hilos que esperan también se planteará la misma excepción.

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

Utilice los siguientes tres métodos, se puede obtener el intérprete para interrumpir la operación cuando un subproceso termina debido a una excepción.

  • script de inicio especifica la opción-d, y el funcionamiento en modo de depuración.
  • Con Thread.abort_on_exception establecer el indicador.
  • Use Thread#abort_on_exception bandera conjunto hilo especificado.

Cuando se utiliza uno de los tres métodos descritos anteriormente, se interrumpirá toda la intérprete.

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

sincronización hilo

En Ruby, proporciona tres de manera sincronizada, a saber:

1. Objeto mutex clase implementa la sincronización de subprocesos

2. Regulador de clase cola de transferencia de datos de la aplicación de sincronización de subprocesos

3. Uso de control de sincronización ConditionVariable

Por mutex clase implementa la sincronización de subprocesos

Por clase objeto mutex implementa el control de sincronización de subprocesos, si también necesita un reloj variable de programa en varios subprocesos, puede utilizar la cerradura para bloquear la parte variable. Código es el siguiente:

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

El código de seguridad se ejecuta como resultado de:

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

Además de utilizar bloqueado bloqueo variable, se puede también utilizar try_lock variable bloqueada, también se puede utilizar Mutex.synchronize sincronizar el acceso a una variable en particular.

la transferencia de datos de prueba de la clase Queue implementa la sincronización de subprocesos

clase de cola que representa una cola de soporte de hilos, la cola se puede sincronizar con el final de la visita. Diferentes hilos pueden utilizar una clase unificada, pero no preocuparse de si los datos se pueden sincronizar en esta cola, además de limitar el uso de SizedQueue longitud de la cola de clase

SizedQueue clase puede ser muy conveniente para ayudarnos a desarrollar aplicaciones de subprocesos para sincronizar, los problemas de sincronización, debe añadirse a la larga cola, que no se preocupan por hilos.

productores y consumidores clásicos:

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

La salida del programa:

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

Variables de subproceso

Hilo puede tener su variable privada, un hilo de rosca variable privada de escritura cuando se crea el hilo. Se puede utilizar dentro del alcance de la rosca, pero el hilo no puede ser compartida externamente.

Pero a veces, las variables locales de rosca no necesitan otro hilo o el hilo principal para acceder a cómo hacerlo? rubí les permite crear un hilo es proporcionada por el nombre de la variable, el hilo es visto como tabla hash hash de estilo similar. Por [] = escrito por [] leer datos. Nos fijamos en el siguiente código:

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

El código anterior se ejecuta salida es:

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

Los principales hilo espera para la ejecución hilo hijo se ha completado, y después hacen salir cada valor. .


prioridad de los hilos

La prioridad del subproceso es el principal factor que afecta la programación de subprocesos. Otros factores incluyen la duración de tiempo para llevar a cabo CPU-hilo de programación de paquetes y así sucesivamente.

Puede utilizar Thread.priority obtiene la prioridad de un hilo y utilizar Thread.priority = método para ajustar la prioridad del hilo.

por defecto la prioridad de un hilo a 0. Más rápida ejecución de más alta prioridad.

Un flujo puede acceder a todos los datos dentro del ámbito de su propia, pero si hay otros hilos necesitan acceder a los datos en un hilo debe ser cómo hacerlo? clase Thread proporciona datos de acceso de hilo entre sí, se puede simplemente poner un hilo como una tabla hash, se puede utilizar en cualquier [] Los datos de rosca = escritura, utilice [] leer datos.

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

Podemos ver, el hilo como una tabla hash, utilice [] y [] = método, hemos logrado el intercambio de datos entre los hilos.


mutex hilo

Mutex (exclusión Mutal = exclusión mutua) es un método para la programación multi-hilo, un mecanismo para evitar que dos hilos simultáneamente por los mismos recursos públicos (tales como variables globales) leer y escribir.

Ejemplos de no utilización 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}"

Ejecutar la salida anterior ejemplo es:

count1 :  9712487
count2 :  12501239
difference : 0

Ejemplo de 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}"

Ejecutar la salida anterior ejemplo es:

count1 :  1336406
count2 :  1336406
difference : 0

punto muerto

Más de dos unidades de operación, ambas partes están esperando a que el otro dejar de correr, para obtener los recursos del sistema, pero no una salida temprana del partido, esta situación se llama punto muerto.

Por ejemplo, un proceso de toma p1 up display, mientras que debe utilizar la impresora y la impresora está ocupada por el proceso P2, P2 también debe utilizar el monitor, formando así un punto muerto.

Cuando usamos objeto mutex objeto necesita estancamiento hilo de atención.

Ejemplos

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

La salida del ejemplo anterior es:

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!

método de la clase Thread

Tema (rosca) método completo de clases de la siguiente manera:

No. Descripción del método
1 Thread.abort_on_exception
Si bien es cierto, una vez al subproceso termina debido a una excepción, se interrumpirá toda la intérprete. El valor predeterminado es falso, es decir, en circunstancias normales, si se produce una excepción de rosca y la excepción no se unen hilo # y otra detectado, el hilo se dará por terminado sin previo aviso.
2 Thread.abort_on_exception =
Si esverdadero,una vez al subproceso termina debido a una excepción, se interrumpirá toda la intérprete. Devuelve nuevo estado
3 Thread.critical
Devuelve un valor booleano.
4 Thread.critical =
Cuando el valor es verdadero, no se cambiará el hilo. Si el subproceso actual para colgar (parada) o la intervención de la señal (señal), su valor será cambiado automáticamente a falso.
5 Thread.current
Devuelve el hilo de ejecución actual (la hebra actual).
6 Thread.exit
Finaliza el hilo actual. Devuelve el hilo actual. Si el hilo actual es el único hilo, usando la salida (0) para terminar su operación.
7 Thread.fork {bloque}
Al igual que con Thread.new generar roscas.
8 Thread.kill (aThread)
Terminar el hilo en ejecución.
9 Thread.list
Devuelve una matriz de hilo en vivo se está ejecutando o estado suspendido.
10 Thread.main
Volver al hilo principal.
11 Thread.new ([arg] *) { | args | block}
Generar hilo y comenzar la ejecución. El número será transmitido intacto al bloque. Esto puede iniciar un hilo, al mismo tiempo, el valor será pasado a las variables locales inherentes al hilo.
12 Thread.pass
El derecho a ejecutar otros hilos. No cambia el estado de los hilos de ejecución, sino que entregar el control de otros hilos se pueden ejecutar (la programación de subprocesos explícita).
13 Hilo.start ([args] *) { | args | block}
Generar hilo y comenzar la ejecución. El número será transmitido intacto al bloque. Esto puede iniciar un hilo, al mismo tiempo, el valor será pasado a las variables locales inherentes al hilo.
14 Thread.stop
El hilo actual se suspende hasta que los otros hilos método ejecutar de nuevo el hilo se despiertan.

método de instancia hilo

El siguiente ejemplo llama al método de instancia hilo se unen:

#!/usr/bin/ruby

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

Aquí está una lista completa de los ejemplos del método:

No. Descripción del método
1 thr [nombre]
Retire el hilo del nombre correspondiente a los datos inherentes. nombre puede ser una cadena o un símbolo. Si el nombre no se corresponde con los datos, devuelve nil.
2 thr [nombre] =
Establecer el valor de nombre de subproceso en los datos característicos correspondientes, el nombre puede ser una cadena o un símbolo. Si se establece en cero, elimina los datos correspondientes en este hilo.
3 thr.abort_on_exception
Devuelve un valor booleano.
4 thr.abort_on_exception =
Si su valor es verdadero, entonces una vez al subproceso termina debido a una excepción, se interrumpirá toda la intérprete.
5 thr.alive?
Si el hilo está "vivo", devuelve true.
6 thr.exit
Terminar el hilo en ejecución. Devuelve uno mismo.
7 thr.join
Suspende el subproceso actual hasta que el auto de ejecución que termine el hilo. Si el auto debido a la terminación anormal, el hilo actual dará lugar a la misma excepción.
8 thr.key?
Si el nombre correspondiente a los datos inherentes ha sido hilos definidos, a continuación, devuelve verdadero
9 thr.kill
Thread.exit similar.
10 thr.priority
Devuelve la prioridad del hilo. La prioridad por defecto es 0. Cuanto mayor sea el valor, mayor será la prioridad.
11 thr.priority =
Establecer la prioridad del hilo. También puede configurarlo para que negativo.
12 thr.raise (anException)
Dentro de este hilo lanzado por la fuerza.
13 thr.run
Aún sin reiniciar hilo (parada). La diferencia es que con la activación del hilo llevará a cabo el cambio de inmediato. Si se utiliza este método para procesar los muertos serán levantados ThreadError excepción.
14 thr.safe_level
Devuelve el nivel de seguridad auto. Safe_level la corriente hilo $ SAFE misma.
15 thr.status
El uso de la cadena "correr", "espera" o "abortar" para indicar el estado de la conversación en vivo si un hilo se termina normalmente, a continuación, devuelve falso. Ruoyin terminación anormal, entonces devuelve nil.
16 thr.stop?
Si el hilo se termina estado (muerto) o suspender (parada), el retorno real.
17 thr.value
Espere hasta que el hilo auto termina (equivalente a unirse), devuelve el valor del bloque del hilo si los hilos de ejecución se producen durante anormal, la excepción se levantó de nuevo.
18 thr.wakeup
El estado se suspende (parada) de hilo al estado preparado (pista), si el método se lleva a cabo en el hilo de muertos aumentará ThreadError excepción.