2011년 6월 2일 목요일

11.Threads and Processes

11.Threads and Processes

멀티스레딩
한 번에 두 가지 일을 동시에 하는 가장 간단한 방법은 루비 스레드를 이용하는 것이다. 루비 스레드는 루비 인터프리터 안에서 구현되었으며 완전하게 이 프로세스 안에서 구동되며, 운영체제에 의존하지 않는다.

루비 스레드 생성하기
아래의 코드는 각각의 URL에 대해 분리된 스레드를 생성하여 HTTP 트랜잭션을 처리한다.

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) { |url|

h = Net::HTTP.new(url, 80)
puts "Fetching: #{url}"
resp, data = h.get('/', nil )
puts "Got #{myPage}: #{resp.message}"
}
end

threads.each { |aThread| aThread.join

Thread.new  호출과 함께 새로운 스레드가 생성된다. 그리고 새로운 스레드에서 실행할 코드를 담은 블록을 적어준다.
스 레드를 생성할 때, 요청 받은 URL을 매개변수로 넘겼다. 이 매개변수는 url이라는 이름으로 블록에 넘겨졌다. page_to_fetch 변수을 블록안에서 직접적으로 사용하지 않는 이유는 생성되는 3개의 스레드에서 모두 공유하게 되고 스레드 블록 안에서 생성된 지역 변수는 스레드에서만 참조 가능하기 때문이다.

스레드 조작하기

- Thread#join
루비 프로그램이 종료되면, 모든 스레드는 자신의 상태와 상관없이 강제로 종료되어 버린다. Thread#join을 호출하면 특정 스레드가 일을 끝마칠 때가지 기다리게 할수 있다. join에 제한시간을 줄 수도 있다.

- Thread.current
현재 스레드에 접근할 수 있다.

- Thread.list
실행중인, 멈춰 있는지에 상관없이 모든 스레드의 목록을 얻을 수 있다.

- Thread#status, Thread#alive?
특정 스레드의 상태를 확인

- Thread#priority=
특정 스레드의 우선순위를 조정

스레드 변수
스레드는 생성되는 시점에서 유효 범위 안에 있는 모든 변수에 정상적으로 접근 할 수 있다. 스레드 코드를 담고 있는 블록 안의 지역 변수는 해당 스레드에만 지역적이고 서로 공유되지 않는다.
Thread 클래스는 스레드 지역 변수를 만들고 이를 이름으로 접근하는 특별한 기능을 지원한다. 마치 스레드 객체가 일종의 해시인 것 처럼 []=을 이용하여 요소를 쓰고, []를 이용하여 읽으면 된다.
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}"
produces:
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10
스레드 스케줄러 제어하기
Thread 클래스는 스레드 스케줄러를 제어하기 위한 메서드를 많이 제공한다.

- Thread.stop
현재 스레드를 멈춘다.

- Thread#run
특정한 스레드가 실행되도록 조정한다.

- Thread.pass
다른 스레드가 실행되도록 현재 스레드를 조정한다.

- Thread#join, Thread#value
주어진 스레드가 끝날 때까지 호출한 스레드의 실행을 연기한다.

상호배제
한 스레드의 실행 중에 다른 스레드가 끼어드는 것을 막는 가장 낮은 수준의 방법은 전역적인 스레드-임계 조건을 사용하는 것이다. Thread.critical= 메서드를 사용하여 조건을 true로 설정하면 스케줄러는 다른 스레드를 스케줄하지 않아 실행을 막을 것이다. 하지만 이것도 새로운 스레드가 생성되어 실행되는 것 까지 막지는 않는다. 스레드-임계 조건 대안으로 사용되는 방법중 하나가 모니터 라이브러리를 사용하는 것이다.

모니터
모니터는 동기화 함수를 가지고 어떤 종류의 자원을 가진 객체를 감싼다.

require 'monitor'
class Counter < Monitor
attr_reader :count
def nitialize
    @count = 0
    super
end
def tick
    synchronize do
   @count +=1
    end
end
end

c= Counter.new
t1 = Thread.new {100_000.times {c.tick}}
t2 = Thread.new {100_000.times {c.tick}}
ti.join; t2.join
c.count -> 200000

Counter 를 모니터로 구현함으로써, synchronize 메서드를 사용할 수 있다. 특정 모니터 객체의 동기화 블록 안에서는 한 순간에 오직 스레드 하나만이 실행되므로, 동시에 두 개의 스레드가 중간 결과를 가져가는 일은 더 이상 발생하지 않는다.
Monitor가 가진 이러한 이점을 취하기 위해 꼭 하위 클래스로 만들어야 하는 것은 아니다. MonitorMixin을 사용해도 된다.

require 'monitor'
class Counter
include MonitorMixin
...
end

다중 프로세스 실행
때 로는 하나의 작업을 크기가 다른 프로세스 덩어리 몇 개로 나누어야 할지도 모른다. 어쩌면 루비가 아닌 다른 언어로 만들어진 별개의 프로세스를 실행해야 할 수도 있다. 루비는 독립적인 프로세스를 생성하거나 관리할 수 있는 여러 가지 방법을 제공하고 있다.

새로운 프로세스 생성
system("tar xzf test.tgz")»true
result = `date`
result»"Sun Jun  9 00:08:50 CDT 2002\n"

루비에서는 system 메서드나 역따옴표 메서드로 명령어를 실행 할 수 있다. Kernel.system 메서드는 주어진 명령을 하위 프로세스에서 실행한다. 명령어가 실제로 존재하고 적절하게 실행되었다면 true을 반환한다.
system이 가진 문제점 하나는 실행한 명령의 출력이 여과 없이 현재 실행 중인 프로그램의 출력으로 전달된다는 것이다. 하위 프로세스의 표준 출력을 가로채기 위해서는 역따옴표 문자를 사용할 수 있다.

IO.popen
하위 프로세스와 대화를 하고, 데이터를 주고받아야 하는 경우에 사용한다. popen 메서드는 하위 프로세스로 명령을 실행하고, 하위 프로세스의 표준 입력과 출력을 루비의 IO 객체와 연결한다.
pig = IO.popen("pig", "w+")
pig.puts "ice cream after they go to bed"
pig.close_write
puts pig.gets
produces:
iceway eamcray afterway eythay ogay otay edbay
pig.close_write는 pig의 표준 입력에 end-of-file을 보내서, pig를 종료시킴으로써 우리가 기다리는 출력을 모두 얻을 수 있게 해준다.

독립적인 자손
때로는 꼭 자식 프로세스에 손을 대고 있어야 할 필요도 없다. 자식 프로세스에게 일을 할당하고, 부모는 자신의 일을 계속하게 하면된다.
exec("sort testfile > output.txt") if fork == nil
# The sort is now running in a child process
# carry on processing in the main program
# then wait for the sort to finish
Process.wait
Kernel.fork 호출은 부모에게는 프로세스 ID를 반환하고, 자식에게는 nil을 반환한다. 그러므로 자식 프로세스는 Kernel.exec 호출을 수행하고 sort를 실행할 것이고, 얼마 후에 sort 명령이 끝나기를 기다리는 Process.wait 호출을 수행한다.

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...