rubi Multithreading
Cada programa em execução no sistema é um processo. Cada processo contém um ou mais segmentos.
Um segmento é um único fluxo de controle do programa seqüencial, em simultâneo executar vários segmentos em um único programa fazer coisas diferentes, chamadas multi-threading.
Ruby, que pode ser criado por múltiplos threads classe Thread, tópicos Ruby são um peso leve, pode ser uma maneira eficiente de implementar o código paralelo.
Criando uma linha de Ruby
Para iniciar um novo tópico, você pode apenas chamar Thread.new:
# 线程 #1 代码部分 Thread.new { # 线程 #2 执行代码 } # 线程 #1 执行代码
Exemplos
O exemplo a seguir mostra como usar multithreading no 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}"
O código acima é executado 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 fio da vida
1, criar um thread pode usar Thread.new, você também pode usar o mesmo Thread.start de sintaxe ou Thread.fork três maneiras de criar um fio.
2, crie uma linha sem iniciar, o segmento será executado automaticamente.
3, classe Thread define métodos para manipular discussão. Fio de blocos de código de execução Thread.new.
4, o bloco da linha é o valor da última declaração no segmento, o segmento pode ser invocado por um método, se o fio for concluída, ele retorna o valor da linha, ou não retorna um valor até que o segmento está terminada.
5, método Thread.current retorna um objeto para a representação atual segmento. Método Thread.main retorna o thread principal.
6, o método é realizado por fios Thread.Join, este método irá suspender o thread principal até que o segmento atual está terminado.
Estado rosca
Thread tem cinco estados:
Estado rosca | Valor de retorno |
---|---|
executável | corrida |
adormecido | adormecido |
desistir | abortando |
terminação normal | falso |
Finalização anormal ocorre | zero |
Fios e aberrante
Quando uma exceção de thread ocorre e nenhum resgate foi capturado, o segmento normalmente seria encerrado sem aviso. No entanto, se outros tópicos Tópico # juntar-se porque a relação tem sido esperando por esta discussão, em seguida, os segmentos de espera também será levantada a mesma exceção.
begin t = Thread.new do Thread.pass # 主线程确实在等join raise "unhandled exception" end t.join rescue p $! # => "unhandled exception" end
Use as seguintes três métodos, você pode obter o intérprete para interromper a operação quando um segmento é encerrado devido a uma exceção.
- script de inicialização especifica opção-d, e operação em modo de depuração.
- Com
Thread.abort_on_exception
definir o sinalizador. - Use
Thread#abort_on_exception
bandeira especificado set discussão.
Quando se utiliza um de três métodos descritos acima, todo o intérprete irá ser interrompido.
t = Thread.new { ... } t.abort_on_exception = true
Sincronização Tópico
Em Ruby, fornece três maneira sincronizada, a saber:
1. Mutex classe implementa sincronização de thread
2. classe Fila de transferência de dados Regulatory implementar a sincronização de threads
controle de sincronização 3. Use ConditionVariable
Por Mutex classe implementa sincronização de thread
Por classe Mutex implementa o controle de sincronização de threads, se você também precisa de um relógio variável de programa em vários segmentos, você pode usar o bloqueio para bloquear a parte variável. Código é a seguinte:
#!/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
O código acima é executado 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
Além de usar locked variável, você também pode usar try_lock variável bloqueada, você também pode usar Mutex.synchronize sincronizar o acesso a uma variável particular.
a transferência de dados de regulamentação da classe Queue implementa sincronização de thread
Fila de classe que representa um segmento fila de suporte, a fila pode ser sincronizado com o fim da visita. Diferentes segmentos podem usar uma classe unificada, mas não se preocupe se os dados podem ser sincronizados nesta fila, além de limitar o uso de SizedQueue comprimento da fila de classe
classe SizedQueue pode ser muito conveniente para nos ajudar a desenvolver aplicações com rosca para sincronizar, problemas de sincronização deve ser adicionado à longa fila, você não se preocupam com threads.
produtores e consumidores clássicos:
#!/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
Programa de saída:
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
Variáveis Thread
Thread pode ter sua variável privada, uma variável privada de discussão escrita segmento quando o segmento é criado. Ele pode ser usado dentro do âmbito da rosca, mas o fio não pode ser partilhada externamente.
Mas, às vezes, as variáveis locais de rosca não precisa de outro segmento ou o segmento principal para acessar como fazer? ruby lhes permite criar uma lista de discussão é fornecido pelo nome da variável, o segmento é visto como estilo semelhante tabela hash hash. Por [] = escrito por [] ler os dados. Nós olhamos para o seguinte 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}"
O código acima é executado saída é:
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10
Os principais thread espera para a execução segmento de criança é concluída, e em seguida, gera cada valor. .
a prioridade do thread
A prioridade da linha é o principal fator que afeta o agendamento de segmento. Outros factores incluem o comprimento de tempo para a realização da CPU fios pacote de programação e assim por diante.
Você pode usar Thread.priority obtido prioridade de um segmento e usar Thread.priority = método para ajustar a prioridade do thread.
defaults prioridade de um segmento para 0. execução mais rápida de maior prioridade.
Um thread pode acessar todos os dados no âmbito da sua própria, mas se houver outros tópicos precisam acessar dados em um segmento deve ser a forma de fazê-lo? classe Thread fornece dados de segmento acessar um ao outro, você pode simplesmente colocar um fio como uma tabela hash, pode ser usado em qualquer segmento [] data = escrita, utilize [] ler os dados.
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, o segmento como uma tabela hash, utilize [] e [] = método, conseguimos partilha de dados entre threads.
mutex rosca
Mutex (Exclusão Mutal = mutex) é um método de programação multi-threaded, um mecanismo para impedir que duas threads simultaneamente para os mesmos recursos públicos (como variáveis globais) ler e escrever.
Exemplos de não utilização 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}"
Execute o exemplo acima saída é:
count1 : 9712487 count2 : 12501239 difference : 0
Exemplo 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}"
Execute o exemplo acima saída é:
count1 : 1336406 count2 : 1336406 difference : 0
impasse
Mais de duas unidades de operação, ambos os lados estão esperando que o outro para parar de correr, para obter os recursos do sistema, mas não uma saída precoce partido, esta situação é chamado de impasse.
Por exemplo, um p1 processo leva up display, enquanto você deve usar a impressora e a impressora está ocupada pelo processo P2, P2 deve também usar o monitor, formando assim um impasse.
Quando usamos Mutex objeto precisa de atenção de impasse thread.
Exemplos
#!/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
O exemplo acima saída é:
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 classe Thread
Tópico (thread) método de classe completa da seguinte forma:
Não. | método Descrição |
---|---|
1 | Thread.abort_on_exception Se é verdade, uma vez que um segmento termina devido a uma exceção, todo o intérprete será interrompido. O valor padrão é falso, isto é, em circunstâncias normais, se uma exceção de thread ocorre e a exceção não é thread # juntar e outra detectado, o fio será encerrada sem aviso. |
2 | Thread.abort_on_exception = Se definido comoverdadeiro,uma vez que um segmento termina devido a uma exceção, todo o intérprete será interrompido. Retorna novo estado |
3 | Thread.critical Retorna um valor booleano. |
4 | Thread.critical = Quando o valor for true, o segmento não será alterado. Se o segmento atual para pendurar (parar) ou sinal de intervenção (sinal), o seu valor será automaticamente alterado para falso. |
5 | Thread.current Retorna o segmento em execução atual (o segmento atual). |
6 | Thread.exit Ele termina o segmento atual. Retorna o atual segmento. Se o segmento atual é o único fio, usando a saída (0) para encerrar o seu funcionamento. |
7 | Thread.fork {block} Como com Thread.new gerar threads. |
8 | Thread.kill (aThread) Encerrar o segmento em execução. |
9 | Thread.list Retorna uma matriz de rosca ao vivo está em execução ou estado suspenso. |
10 | Thread.main Voltar para o segmento principal. |
11 | Thread.new ([arg] *) { | args | block} Gerar fio e começar a execução. O número será transmitida intacta para o bloco. Isto pode iniciar um segmento, ao mesmo tempo, o valor será passado para as variáveis locais inerentes ao fio. |
12 | Thread.pass O direito de executar outros tópicos. Isso não muda o estado das threads em execução, mas vai entregar o controle de outros segmentos podem ser executados (programação explícita thread). |
13 | Thread.start ([args] *) { | args | block} Gerar fio e começar a execução. O número será transmitida intacta para o bloco. Isto pode iniciar um segmento, ao mesmo tempo, o valor será passado para as variáveis locais inerentes ao fio. |
14 | Thread.stop O thread atual é suspenso até que os outros segmentos método run novamente acorda o segmento. |
método de instância de discussão
O exemplo a seguir chama o método de instância de discussão juntar-se:
#!/usr/bin/ruby thr = Thread.new do # 实例化 puts "In second thread" raise "Raise exception" end thr.join # 调用实例化方法 join
Aqui está uma lista completa de exemplos do método:
Não. | método Descrição |
---|---|
1 | thr [nome] Remova a linha do nome correspondente aos dados inerentes. nome pode ser uma string ou símbolo. Se o nome não corresponder aos dados, ele retorna nulo. |
2 | thr [nome] = Defina o valor do nome de rosca nos dados característicos correspondentes, o nome pode ser uma string ou símbolo. Se definido como nil, remove os dados correspondentes neste segmento. |
3 | thr.abort_on_exception Retorna um valor booleano. |
4 | thr.abort_on_exception = Se o valor for verdade, então uma vez por segmento é encerrado devido a uma exceção, todo o intérprete será interrompido. |
5 | thr.alive? Se o segmento é "ao vivo", ele retorna true. |
6 | thr.exit Encerrar o segmento em execução. Retorna self. |
7 | thr.join Suspende o segmento atual até que o auto run até que o segmento termina. Se o auto devido à finalização anormal, o segmento atual irá desencadear a mesma exceção. |
8 | thr.key? Se o nome correspondente aos dados inerentes tem sido tópicos definidos, em seguida, retorna true |
9 | thr.kill Thread.exit similares. |
10 | thr.priority Retorna a prioridade do segmento. A prioridade padrão é 0. Quanto maior o valor, maior a prioridade. |
11 | thr.priority = Definir a prioridade segmento. Você também pode configurá-lo para negativo. |
12 | thr.raise (anException) Dentro deste segmento forçosamente lançada. |
13 | thr.run Reinicie Pendente thread (stop). A diferença é que com a excitação vai realizar segmento de comutação imediatamente. Se usar este método para processar os mortos serão levantados exceção ThreadError. |
14 | thr.safe_level Retorna nível de auto segurança. Safe_level a corrente fio $ SAFE mesma. |
15 | thr.status Usando a cadeia "run", "sono" ou "abortar" para indicar o estado do fio vivo se um segmento é encerrado normalmente, então ele retorna false. Ruoyin finalização anormal, em seguida, retorna nil. |
16 | thr.stop? Se o segmento é encerrado Estado (morto) ou suspender (stop), o retorno verdadeiro. |
17 | thr.value Espere até que o segmento de auto termina (equivalente a juntar-se), devolver o valor do bloco do fio se as threads em execução ocorrer durante anormal, a exceção será levantada novamente. |
18 | thr.wakeup O estado é suspenso (parar) de fio para o estado de pronto (pista), se o método é realizado no segmento de mortos vai aumentar ThreadError exceção. |