프로그램의 서로 다른 영역을 '동시에' 실행할 수 있도록 프로그램을 구성하는 두가지 기본 방법을 제공
- Multy Threading : 한 프로그램 안에서 협업이 가능한 일을 분리해서 실행
- Multy Process : 작업을 서로 다른 프로그램으로 분리
Ruby Thread
- Thread.new 호출과 함께 새로운 Thread를 생성
- Thread.join으로 각 Thread의 종결을 기다림 : Thread.join의 호출이 되지 않고 Ruby 프로그램이 종료되면 모든 Thread가 종결된다. - python과 동일하다.
- Thread에서 실행될 코드를 적어서 실행하여 준다.
- Thread.current : 현재 Thread
- Thread.list : 모든 Thread의 List를 얻어낼 수 있다.
- Thread.prioirty를 이용해서 Thread의 우선 순위를 조정 가능하다.
- Ruby Thread는 일종의 Hash와 동일하게 사용가능하고 이는 []=를 이용해서 요소를 쓰고, []를 이용해서 요소를 얻어낼 수 있다.
require 'net/http' pages = %w{ www.rubycentral.com slashdot.org www.google.com } threads = [] for page_to_fetch in pages threads << Thread.new(page_to_fetch) do |url| h = Net::HTTP.new(url, 80) puts "Fetching : #{url}" resp = h.get('/', nil) puts "Got #{url}: #{resp.message}" end end threads.each { |thr| thr.join }
count = 0 threads = [] 10.times do |i| threads[i] = Thread.new do sleep(rand(0.1)) Thread.current["mycount"] = count count += 1 end end threads.each { |t| t.join; print t["mycount"], ", " } puts "count = #{count}"
Thread Schedule Control
- Thread#stop : Thread를 stop
- Thread#run : 특정 Thread를 실행하도록 제어
- Thread.new에서 Thread.stop으로 넣어지면, 정지된 상태에서의 Thread로 생성된다.
class Chaser attr_reader :count def initialize(name) @name = name @count = 0 end def chase(other) while @count < 5 while @count - other.count > 1 Thread.pass end @count += 1 print "#@name : #{count} \n" end end end c1 = Chaser.new("A") c2 = Chaser.new("B") threads = [ Thread.new{ Thread.stop; c1.chase(c2) }, Thread.new{ Thread.stop; c2.chase(c1) } ] start_index = rand(2) threads[start_index].run threads[1 - start_index].run threads.each{ |t| t.join }
: Thread의 동작 제어의 경우에는 전에 사용되던 내용과 거의 유사 -> python, C# 등과 거의 유사하다는 생각이 든다.
Thread-Critical
- 전역적인 Thread-critical 을 사용한다.
- Thread.critical=true 로 설정시켜준다.
- Monitor, Mutex_m, Sync 라이브러리를 이용하면, 다른 방법을 이용해서 얻는 것이 가능하다.
Monitor
- Monitor class를 상속 받아서 synchronize 를 이용
- MonitorMixin을 사용
require 'monitor' class Counter < Monitor attr_reader :count def initialize @count = 0 super end def tick synchronize do @count += 1 print @count end end end c = Counter.new t1 = Thread.new { 10000.times { c.tick() } } t2 = Thread.new { 1000.times { c.tick() } } t1.join ; t2.join print c.count
require 'monitor' class Counter attr_reader :count include MonitorMixin def initialize @count = 0 super end def tick synchronize do @count += 1 print @count end end end c = Counter.new t1 = Thread.new { 10000.times { c.tick() } } t2 = Thread.new { 1000.times { c.tick() } } t1.join ; t2.join print c.count
class의 Monitor 만들기
require 'monitor' class Counter attr_reader :count def initialize @count = 0 super end def tick @count += 1 print @count end end c = Counter.new
c.extend(MonitorMixin)
t1 = Thread.new { 10000.times { c.synchronize{ c.tick() } } }
t2 = Thread.new { 1000.times { c.synchronize{ c.tick() } } } t1.join ; t2.join print c.count
module의 extend를 이용해서 MonitorMixin을 include 시켜서 만들어준다.