채널과 코루틴
채널은 동시 작업 사이에서 값을 교환합니다. 버퍼드 또는 언버퍼드 방식으로 사용할 수 있으며, channel.select와 결합해 여러 작업을 조율할 수 있습니다.
이 페이지는 API 참조입니다. 기본 블록은 독립적인 코드 조각이며, 타임아웃, fan-in, 논블로킹 섹션은 주변 애플리케이션에서 이름 있는 채널과 콜백을 제공하는 부분 패턴입니다. 워커 풀 블록은 완전한 프로세스 내부 예제입니다.
channel과 coroutine 전역은 항상 사용할 수 있습니다. 채널은 하나의 Lua 프로세스 안에서 코루틴을 조율합니다. 프로세스 경계를 넘을 때는 프로세스 메시징, 함수 또는 큐를 사용하세요.
채널 생성
언버퍼드 채널(크기 0)은 전송이 완료되기 전에 송신자와 수신자가 모두 준비되어야 합니다. 버퍼드 채널은 버퍼 공간이 있는 동안 전송을 완료할 수 있습니다.
-- Unbuffered: synchronizes sender and receiver
local sync_ch = channel.new()
-- Buffered: queue up to 10 messages
local work_queue = channel.new(10)
| 파라미터 | 타입 | 설명 |
|---|---|---|
size |
integer | 버퍼 용량 (기본값: 0, 언버퍼드) |
반환: channel
값 보내기
언버퍼드 채널에서는 수신자가 준비될 때까지, 버퍼드 채널에서는 버퍼 공간이 생길 때까지 전송이 블록됩니다.
-- Send work to a worker pool
local tasks = {"task-a", "task-b"}
local jobs = channel.new(100)
for i, task in ipairs(tasks) do
jobs:send(task) -- Blocks if buffer full
end
jobs:close() -- Signal no more work
| 파라미터 | 타입 | 설명 |
|---|---|---|
value |
any | 보낼 값 |
반환: boolean
닫힌 채널에 전송하면 오류가 발생합니다.
값 받기
값을 사용할 수 있거나 채널이 닫힐 때까지 수신이 블록됩니다.
-- Worker consuming from job queue
while true do
local job, ok = jobs:receive()
if not ok then
break -- Channel closed, no more work
end
process(job)
end
여기서 jobs는 애플리케이션이 제공하는 큐이고 process는 작업 처리 콜백입니다.
반환: any, boolean
value, true— 값을 받음nil, false— 채널이 닫히고 비어 있음
채널 닫기
채널을 닫으면 대기 중인 송신자는 오류를 받고 대기 중인 수신자는 nil, false를 받습니다. 이미 닫힌 채널을 닫는 작업은 아무 효과가 없습니다.
local results = channel.new(10)
-- Producer fills results
for _, item in ipairs(data) do
results:send(process(item))
end
results:close() -- Signal completion
이 독립적인 생산자 조각은 애플리케이션이 data와 process 콜백을 제공한다고 가정합니다.
여러 채널에서 Select
channel.select는 여러 채널 작업을 동시에 기다립니다. 이벤트 소스, 타임아웃, 논블로킹 확인을 조율할 수 있습니다.
local result = channel.select(cases)
| 파라미터 | 타입 | 설명 |
|---|---|---|
cases |
table | select 케이스 배열 |
default |
boolean | true이면 준비된 케이스가 없을 때 즉시 반환 |
반환: table
- 채널 케이스의 경우:
{channel, value, ok}—channel은 해당 케이스의 채널,value는 수신/전송된 값,ok는 닫힌 채널에서 수신한 경우 false입니다. - 기본 분기의 경우(준비된 케이스가 없고
default = true일 때):{default = true, ok = true}.
타임아웃 패턴
time.after()를 사용하여 채널 대기에 타임아웃을 추가합니다.
local time = require("time")
local result_ch = application_response_channel
local timeout, err = time.after("5s")
if err then
return nil, err
end
local r = channel.select {
result_ch:case_receive(),
timeout:case_receive()
}
if r.channel == timeout then
return nil, errors.new({ kind = errors.TIMEOUT, message = "Operation timed out" })
end
return r.value
이 부분 패턴은 엔트리의 modules:에 time이 있고 애플리케이션이 application_response_channel을 제공한다고 가정합니다. time.after는 성공 시 하나의 채널을 반환하며, 유효하지 않거나 양수가 아닌 기간에는 nil, error를 반환합니다.
Fan-in 패턴
한 루프에서 여러 소스의 값을 처리합니다.
이 프로세스 엔트리 패턴은 주변 process를 사용하며, 애플리케이션이 종료 신호와 두 핸들러 함수를 제공합니다.
local events = process.events()
local inbox = process.inbox()
local shutdown = channel.new()
while true do
local r = channel.select {
events:case_receive(),
inbox:case_receive(),
shutdown:case_receive()
}
if r.channel == shutdown then
break
elseif r.channel == events then
handle_event(r.value)
else
handle_message(r.value)
end
end
논블로킹 확인
기본 케이스를 사용하여 블로킹 없이 사용 가능한 데이터를 확인합니다.
이 독립적인 패턴에서 ch와 process 콜백은 애플리케이션이 제공합니다.
local r = channel.select {
ch:case_receive(),
default = true
}
if r.default then
-- Nothing available, do something else
elseif not r.ok then
-- The channel is closed
else
process(r.value)
end
Select 케이스 생성
channel.select와 함께 사용할 케이스 생성:
-- Send case - completes when channel can accept value
ch:case_send(value)
-- Receive case - completes when value available
ch:case_receive()
케이스 테이블에서 송신 또는 수신 케이스가 아닌 값은 무시됩니다. 기본 분기가 없다면 테이블에 유효한 케이스를 하나 이상 포함하세요.
워커 풀 패턴
local items = {1, 2, 3, 4}
local num_workers = 2
local function process_item(item)
return item * 2
end
local work = channel.new(#items)
local results = channel.new(#items)
-- Spawn workers
for _ = 1, num_workers do
coroutine.spawn(function()
while true do
local item, ok = work:receive()
if not ok then
return
end
results:send(process_item(item))
end
end)
end
-- Feed work
for _, item in ipairs(items) do
work:send(item)
end
work:close()
-- Collect results
local processed = {}
while #processed < #items do
local result, ok = results:receive()
if not ok then break end
table.insert(processed, result)
end
루프가 끝나면 processed에는 2, 4, 6, 8이 포함되며 결과 순서는 코루틴 스케줄링에 따라 달라집니다. 워커는 같은 Lua 프로세스의 코루틴이므로 채널을 공유합니다.
에러
| 조건 | 종류 | 재시도 가능 |
|---|---|---|
| 닫힌 채널에 Send | 런타임 에러 | 아니오 |
select의 cases 인수가 테이블이 아님 |
런타임 에러 | 아니오 |