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