Latest web development tutorials

Рубин Многопоточность

Каждая программа, работающая на системе является процессом. Каждый процесс содержит один или несколько потоков.

Поток представляет собой единый последовательный поток управления программой, одновременно запускать несколько потоков в одной программе делать разные вещи, называемые многопоточность.

Рубин, мы можем быть созданы несколько классов темы, Ruby нити легкий, он может быть эффективным способом для реализации параллельного кода.


Создание потока на Ruby

Чтобы начать новую тему, вы можете просто позвонить Thread.new:

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

примеров

В следующем примере показано, как использовать многопоточность в программе 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}"

Приведенный выше код выполняется в результате:

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

Жизнь Тема цикла

1, создать поток может использовать Thread.new, вы также можете использовать один и тот же синтаксис Thread.start или Thread.fork три способа создания потока.

2, создать поток без запуска, поток будет выполняться автоматически.

3, класс резьбы определяет методы для манипулирования нить. Тема блоков кода выполнения Thread.new.

4, блок нить значение последнего оператора в потоке, поток может быть вызван методом, если поток завершается, он возвращает значение потока, или не возвращает значение, пока поток не будет закончена.

5, метод Thread.current возвращает объект для текущего представления потоков. Thread.main метод возвращает основной поток.

6, способ осуществляют с помощью Thread.join нитей, этот метод будет приостановить основной поток, пока текущий поток не будет закончена.


Государство Thread

Тема имеет пять состояний:

Государство Thread Возвращаемое значение
исполнимый пробег
спальный спальный
выход прерывании
Нормальное завершение ложный
Аварийное завершение происходит ноль

Нитки и аберрантное

Когда происходит исключение нити, и никакого спасения не был взят в плен, то поток, как правило, прекращается без предупреждения. Однако, если другие темы # присоединиться, потому что отношения ждали этой темы, то ожидающие потоки также будет поднята то же исключение.

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

Используйте следующие три метода, вы можете получить интерпретатор, чтобы прервать операцию, когда поток завершается из-за исключения.

  • Запуск сценария определяет параметр-d, и работу в режиме отладки.
  • С Thread.abort_on_exception установить флаг.
  • Использование Thread#abort_on_exception указанный набор нить флаг.

При использовании одного из трех способов, описанных выше, весь интерпретатор будет прервана.

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

Синхронизация потоков

В Ruby, обеспечивает три синхронизированным образом, а именно:

1. Класс Mutex реализует синхронизацию потоков

2. Нормативная передачи данных класса Queue осуществить синхронизацию потоков

Контроль синхронизации 3. Используйте ConditionVariable

По Mutex класс реализует синхронизацию потоков

По классу Mutex реализует контроль синхронизации потоков, если вам также нужна переменная часы программы в несколько потоков, вы можете использовать замок для блокировки переменной части. Код выглядит следующим образом:

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

Приведенный выше код выполняется в результате:

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

В дополнение к использованию замок заперт переменной, вы можете также использовать try_lock запертую переменную, вы можете также использовать Mutex.synchronize синхронизации доступа к конкретной переменной.

Нормативная передачи данных класса Queue реализует синхронизацию потоков

класс Queue, который представляет собой очередь поддержки потоков, очередь может быть синхронизирован с конца визита. Различные потоки могут использовать единый класс, но не беспокойтесь о том, являются ли данные могут быть синхронизированы в этой очереди, кроме того, чтобы ограничить использование длины очереди класса SizedQueue

SizedQueue класс может быть очень удобно, чтобы помочь нам в разработке многопоточных приложений для синхронизации, проблемы синхронизации должны быть добавлены к длинной очереди, вы не заботитесь о потоках.

Классические производители и потребители:

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

Вывод программы:

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

Переменные темы

Тема может иметь свою частную переменную, поток частной переменной поток записи, когда создается поток. Он может быть использован в пределах нити, но нить не может совместно использоваться наружно.

Но иногда, нить локальные переменные не нужно на другой поток или основной поток, чтобы получить доступ, как это сделать? рубин позволяет им создавать поток обеспечивается именем переменной, поток рассматривается как подобный стиль хэш хэш-таблицы. Согласно [] = написан [] читать данные. Мы смотрим на следующий код:

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

Приведенный выше код выполняется выход:

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

Основной поток ожидает выполнение дочернего потока завершается, а затем выводит каждое значение. ,


приоритет резьбы

Приоритет потока является основным фактором, влияющим на планирование потоков. Другие факторы включают в себя интервал времени, чтобы выполнить планирование пакетов ЦП-потоков и так далее.

Вы можете использовать Thread.priority получают приоритет нити и использовать Thread.priority = метод, чтобы настроить приоритет потока.

приоритета по умолчанию волоске до 0. Быстрее исполнение с более высоким приоритетом.

Поток может получить доступ ко всем данным в пределах своих собственных, но если есть другие потоки должны получить доступ к данным в потоке должно быть, как это сделать? класс резьбы предоставляет данные потоков доступ друг к другу, вы можете просто положить нить в качестве хэш-таблицы, могут быть использованы в любом потоке [] = данные писать, использовать [] читать данные.

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

Мы можем видеть, нить в качестве хэш-таблицу, используйте [] и [] = метод, мы достигли совместного использования данных между потоками.


мьютекс резьбы

Mutex (Муталь = Исключение мьютекс) представляет собой метод многопоточного программирования, механизм для предотвращения двух потоков одновременно для одних и тех же государственных ресурсов (например, глобальные переменные) читать и писать.

Примеры неиспользуемом 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}"

Запуск в приведенном выше примере выход:

count1 :  9712487
count2 :  12501239
difference : 0

Пример 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}"

Запуск в приведенном выше примере выход:

count1 :  1336406
count2 :  1336406
difference : 0

тупик

Более двух оперативных подразделений, обе стороны ждут другого, чтобы остановить бег, чтобы получить системные ресурсы, но не партийную ранний выход, эта ситуация называется тупиковой.

Например, p1 процесс занимает дисплей, в то время как вы должны использовать принтер, и принтер занят процессом р2, р2 должны также использовать монитор, тем самым образуя затор.

Когда мы используем мьютекс объект требует внимания нити тупика.

примеров

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

В приведенном выше примере выход:

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!

Метод класса Thread

Полная нить (нить) метод класса следующим образом:

Нет. Метод Описание
1 Thread.abort_on_exception
Если это правда, как только поток завершается из-за исключения, весь интерпретатор будет прервана. Значение по умолчанию является ложным, то есть, при нормальных обстоятельствах, если исключение происходит и нить исключение не Thread # присоединиться и другие обнаружены, то поток будет прекращено без предупреждения.
2 Thread.abort_on_exception =
Если установлено значениеистинно,как только поток завершается из - за исключения, весь интерпретатор будет прервана. Возвращает новое состояние
3 Thread.critical
Возвращает логическое значение.
4 Thread.critical =
Если значение верно, то поток не будет включен. Если текущий поток повесить (стоп) или (сигнал) вмешательства, его значение будет автоматически изменено на ложь.
5 Thread.current
Возвращает текущий выполняемый поток (текущий поток).
6 Thread.exit
Завершает текущий поток. Возвращает текущий поток. Если текущий поток является единственной нити, используя выход (0), чтобы прекратить его работу.
7 Thread.fork {блок}
Как и с Thread.new генерировать потоки.
8 Thread.kill (AThread)
Прервать текущую нить.
9 Thread.list
Возвращает массив живой работает поток или взвешенном состоянии.
10 Thread.main
Возврат к главному потоку.
11 Thread.new ([аргумент] *) { | агдз | блок}
Создавать поток и начать выполнение. Номер будет принят без изменений в блок. Это может запустить поток в то же время, то значение будет передано в локальных переменных, присущих резьбе.
12 Thread.pass
Право запускать другие темы. Это не изменяет состояние запущенных потоков, но будет передать контроль над другими потоками может работать (Явное планирование потоков).
13 Thread.start ([арг] *) { | агдз | блок}
Создавать поток и начать выполнение. Номер будет принят без изменений в блок. Это может запустить поток в то же время, то значение будет передано в локальных переменных, присущих резьбе.
14 Thread.stop
Текущий поток приостанавливается до тех пор, другие потоки запустить метод снова просыпаются нить.

Метод экземпляра резьбы

В следующем примере вызывается метод экземпляра резьбы присоединения:

#!/usr/bin/ruby

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

Здесь вы сможете найти полный перечень примеров способа:

Нет. Метод Описание
1 Чет [имя]
Удалите нить имя, соответствующее присущего данным. Имя может быть строкой или символ. Если имя не соответствует данным, она возвращает ноль.
2 Чет [имя] =
Установите значение имя потока в соответствующих характеристических данных, имя может быть строка или символ. Если установлено значение ноль, удаляет соответствующие данные в этой теме.
3 thr.abort_on_exception
Возвращает логическое значение.
4 thr.abort_on_exception =
Если его значение истинно, то, как только поток завершается из-за исключения, весь интерпретатор будет прервана.
5 thr.alive?
Если нить "живой", он возвращает истину.
6 thr.exit
Прервать текущую нить. Возвращает себя.
7 thr.join
Приостановка текущий поток до тех пор пока сам перспективе, пока поток не завершит свою работу. Если само из-за ненормального завершения работы, текущий поток вызовет такое же исключение.
8 thr.key?
Если имя, соответствующее присущего данным были определены потоки, а затем возвращает истину
9 thr.kill
ПодобныйThread.exit.
10 thr.priority
Возвращает приоритет потока. Приоритет по умолчанию равен 0. Чем больше значение, тем выше приоритет.
11 thr.priority =
Установка приоритета потока. Вы также можете установить его отрицательным.
12 thr.raise (anException)
В этой теме насильно выброшены.
13 thr.run
Перезапуск Pending (стоп) нить. Разница заключается в том, что с пробуждении будет проводить нить сразу переключения. При использовании этого метода, чтобы обрабатывать мертвые воскреснут ThreadError исключение.
14 thr.safe_level
Возвращает уровень собственной безопасности. Safe_level текущий поток $ SAFE же.
15 thr.status
Используя строку "Выполнить", "сна" или "ABORTING", чтобы указать статус живой нити, если поток завершается нормально, то он возвращает ложь. Ruoyin аварийное завершение, то он возвращает ноль.
16 thr.stop?
Если поток прекращается состояние (мертвую) или приостановить (стоп), возвращение истинного.
17 thr.value
Подождите, пока само поток не прекращается (эквивалент присоединиться), возвращает значение блока нити, если запущенные потоки происходят во время ненормальным, исключение будет поднят снова.
18 thr.wakeup
Состояние приостанавливается (стоп) нити в состоянии готовности (хода), если метод выполняется на мертвом нить поднимет ThreadError исключение.