잊지 않겠습니다.

프로그램의 서로 다른 영역을 '동시에' 실행할 수 있도록 프로그램을 구성하는 두가지 기본 방법을 제공

  • 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 and Exception

 Debug Flag, abort_on_exception flag에 따라서 Thread에서의 Exception이 같이 설정된다.

 

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 시켜서 만들어준다.

 

 

Multi-Process

Create New Process

명령을 실행하고 기다리기 (execute and waiting..)

  • ``을 이용
  • Kernel.system 이용

 

exec("sort testfile > output.txt") if fork.nil?

# 내부에서는 자식 Process에서 돌아가게 된다.

Process.wait #자식의 Process를 기다리는 상태

 

 


Posted by Y2K
,