버퍼드 비동기 채널
버퍼드 비동기 채널 (Buffered Asynchronous Channels)
비동기 채널은 일반 채널과 달리 값을 버퍼링해서, 보내는 연산이 받는 연산을 기다리지 않아도 돼요. 값을 쌓아 두었다가 필요할 때 꺼내 쓰는 소비자-생산자 패턴에 유용하죠.
출처: Racket Reference
본문
11.2.4 버퍼드 비동기 채널
(require racket/async-channel)
package: base
이 섹션에 문서화된 바인딩들은 racket/async-channel 라이브러리가 제공해요. racket/base나 racket이 제공하는 게 아니라는 점에 주의할게요.
11.2.4.1 비동기 채널 만들기와 사용하기
Thread Mailboxes도 참고하세요.
비동기 채널은 채널과 비슷하지만, 보내는 연산이 받는 연산을 기다리지 않도록 값을 버퍼링합니다. 비동기 채널 전용 프로시저와 함께 쓰는 것 외에도, 비동기 채널은 동기화 가능 이벤트로 사용할 수 있어요 (이벤트 참고). async-channel-get이 블록되지 않을 때 비동기 채널은 동기화 준비가 된 상태이고, 비동기 채널의 동기화 결과는 async-channel-get의 결과와 같습니다.
async-channel?
(async-channel? v) → boolean?
v : any/c
v가 비동기 채널이면 #t를, 그렇지 않으면 #f를 반환합니다.
make-async-channel
(make-async-channel [limit]) → async-channel?
limit : (or/c exact-positive-integer? #f) = #f
limit개의 항목 버퍼 한계를 가진 비동기 채널을 반환합니다. get 연산은 채널이 비어 있으면 블록하고, put 연산은 채널에 이미 limit개의 항목이 있으면 블록합니다. limit이 #f이면 채널 버퍼에 한계가 없어서(따라서 put은 결코 블록하지 않습니다) put은 블록되지 않습니다.
async-channel-get
(async-channel-get ach) → any/c
ach : async-channel?
ach에 값이 하나 이상 사용 가능해질 때까지 블록한 뒤, async-channel에 넣어진 값들 중 첫 번째 값을 반환합니다.
async-channel-try-get
(async-channel-try-get ach) → any/c
ach : async-channel?
ach에 값이 하나 이상 즉시 사용 가능하면, ach에 넣어진 값들 중 첫 번째 값을 반환합니다. async-channel이 비어 있으면 결과는 #f입니다.
async-channel-put
(async-channel-put ach v) → void?
ach : async-channel?
v : any/c
v를 ach에 넣습니다. ach의 버퍼가 가득 차 있으면 공간이 생길 때까지 블록합니다.
async-channel-put-evt
(async-channel-put-evt ach v) → evt?
ach : async-channel?
v : any/c
(async-channel-put ach v)가 값을 반환할 때(즉, 채널이 이미 그 한계보다 더 적은 값을 담고 있을 때) 동기화 준비가 되는 동기화 가능 이벤트를 반환합니다. 비동기 채널-put 이벤트의 동기화 결과는 그 비동기 채널-put 이벤트 자신입니다.
예시:
(define (server input-channel output-channel)
(thread (lambda ()
(define (get)
(async-channel-get input-channel))
(define (put x)
(async-channel-put output-channel x))
(define (do-large-computation)
(sqrt 9))
(let loop ([data (get)])
(case data
[(quit) (void)]
[(add) (begin
(put (+ 1 (get)))
(loop (get)))]
[(long) (begin
(put (do-large-computation))
(loop (get)))])))))
(define to-server (make-async-channel))
(define from-server (make-async-channel))
> (server to-server from-server)
#<thread>
> (async-channel? to-server)
#t
> (printf "Adding 1 to 4\n")
Adding 1 to 4
> (async-channel-put to-server 'add)
> (async-channel-put to-server 4)
> (printf "Result is ~a\n" (async-channel-get from-server))
Result is 5
> (printf "Ask server to do a long computation\n")
Ask server to do a long computation
> (async-channel-put to-server 'long)
> (printf "I can do other stuff\n")
I can do other stuff
> (printf "Ok, computation from server is ~a\n"
(async-channel-get from-server))
Ok, computation from server is 3
> (async-channel-put to-server 'quit)
11.2.4.2 비동기 채널의 계약과 임퍼서네이터
async-channel/c
(async-channel/c c) → contract?
c : contract?
비동기 채널을 인식하는 계약을 반환합니다. 채널에 넣어지거나 채널에서 꺼내진 값은 c와 일치해야 합니다.
c 인자가 평탄(flat) 계약이거나 chaperone 계약이면 결과는 chaperone 계약입니다. 그렇지 않으면 결과는 impersonator 계약입니다.
async-channel/c 계약이 비동기 채널에 적용되면, 결과는 입력과 eq?가 아닙니다. 결과는 계약의 종류에 따라 입력의 chaperone 또는 impersonator가 됩니다.
impersonate-async-channel
(impersonate-async-channel channel get-proc put-proc prop prop-val ... ...)
→ (and/c async-channel? impersonator?)
channel : async-channel?
get-proc : (any/c . -> . any/c)
put-proc : (any/c . -> . any/c)
prop : impersonator-property?
prop-val : any
async-channel-get과 async-channel-put 연산을 리다이렉트하는 channel의 impersonator를 반환합니다.
get-proc는 async-channel-get이 channel에서 만들어 내는 값을 받아야 하고, impersonator에서의 get 연산 결과가 되는 대체 값(replacement value)을 만들어 내야 합니다.
put-proc는 channel에 대해 호출된 async-channel-put에 전달된 값을 받아야 하고, 원래 채널에서 호출된 put 프로시저에 전달되는 대체 값을 만들어 내야 합니다.
get-proc와 put-proc 프로시저는 채널에서 값을 얻거나 넣는 모든 연산에 대해 호출됩니다. async-channel-get과 async-channel-put에만 국한되지 않아요.
prop와 prop-val의 쌍(impersonate-async-channel의 인자 개수는 홀수여야 함)은 channel의 impersonator 속성을 추가하거나 그 속성 값을 재정의합니다.
chaperone-async-channel
(chaperone-async-channel channel get-proc put-proc prop prop-val ... ...)
→ (and/c async-channel? chaperone?)
channel : async-channel?
get-proc : (any/c . -> . any/c)
put-proc : (any/c . -> . any/c)
prop : impersonator-property?
prop-val : any
impersonate-async-channel과 같지만, get-proc 프로시저는 원래 값과 같거나 원래 값의 chaperone인 값을 만들어 내야 하고, put-proc도 원래 값과 같거나 원래 값의 chaperone인 값을 만들어 내야 합니다.