버퍼드 비동기 채널

버퍼드 비동기 채널 (Buffered Asynchronous Channels)

비동기 채널은 일반 채널과 달리 값을 버퍼링해서, 보내는 연산이 받는 연산을 기다리지 않아도 돼요. 값을 쌓아 두었다가 필요할 때 꺼내 쓰는 소비자-생산자 패턴에 유용하죠.

출처: Racket Reference

본문

11.2.4 버퍼드 비동기 채널

(require racket/async-channel)

package: base

이 섹션에 문서화된 바인딩들은 racket/async-channel 라이브러리가 제공해요. racket/baseracket이 제공하는 게 아니라는 점에 주의할게요.

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

vach에 넣습니다. 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-getasync-channel-put 연산을 리다이렉트하는 channel의 impersonator를 반환합니다.

get-procasync-channel-getchannel에서 만들어 내는 값을 받아야 하고, impersonator에서의 get 연산 결과가 되는 대체 값(replacement value)을 만들어 내야 합니다.

put-procchannel에 대해 호출된 async-channel-put에 전달된 값을 받아야 하고, 원래 채널에서 호출된 put 프로시저에 전달되는 대체 값을 만들어 내야 합니다.

get-procput-proc 프로시저는 채널에서 값을 얻거나 넣는 모든 연산에 대해 호출됩니다. async-channel-getasync-channel-put에만 국한되지 않아요.

propprop-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인 값을 만들어 내야 합니다.

더 알아보기