Learning
레슨 4 / 8·3개 토픽

코루틴과 에러 처리

코루틴 기초

코루틴(coroutine)은 Lua의 협력적 멀티태스킹 메커니즘입니다. 일반 함수와 달리 실행 중간에 멈추고(yield) 나중에 다시 이어서(resume) 실행할 수 있습니다. 게임 루프, 비동기 작업, 이터레이터 구현 등에 활용됩니다.

lua
-- 코루틴 생성과 실행
local co = coroutine.create(function(name)
    print("안녕, " .. name)
    coroutine.yield()  -- 여기서 멈춤
    print("다시 돌아왔어, " .. name)
    coroutine.yield("결과값")
    print("마지막 실행")
end)

print(coroutine.status(co))        -- "suspended"
coroutine.resume(co, "Lua")        -- "안녕, Lua"
print(coroutine.status(co))        -- "suspended"
coroutine.resume(co)               -- "다시 돌아왔어, Lua"
coroutine.resume(co)               -- "마지막 실행"
print(coroutine.status(co))        -- "dead"

coroutine.wrap과 이터레이터

coroutine.wrap은 코루틴을 일반 함수처럼 호출할 수 있게 감싸줍니다. 이를 활용하면 커스텀 이터레이터를 쉽게 만들 수 있습니다.

lua
-- wrap으로 이터레이터 만들기
local function range(start, stop, step)
    step = step or 1
    return coroutine.wrap(function()
        for i = start, stop, step do
            coroutine.yield(i)
        end
    end)
end

for num in range(1, 10, 2) do
    io.write(num .. " ")  -- 1 3 5 7 9
end
print()

-- yield로 값 주고받기
local co = coroutine.wrap(function()
    local sum = 0
    while true do
        local value = coroutine.yield(sum)
        if not value then break end
        sum = sum + value
    end
end)

co()           -- 초기 실행 (첫 yield까지)
print(co(10))  -- 10
print(co(20))  -- 30
print(co(5))   -- 35

에러 처리: pcall과 xpcall

Lua에서 런타임 에러가 발생하면 프로그램이 즉시 중단됩니다. pcall(protected call)은 에러를 잡아서 프로그램이 계속 실행되도록 합니다. xpcall은 에러 핸들러 함수를 추가로 지정할 수 있습니다.

lua
-- pcall: 보호된 호출
local ok, result = pcall(function()
    return 10 / 0  -- Lua에서 inf 반환 (에러 아님)
end)
print(ok, result)  -- true  inf

-- 에러를 발생시키는 경우
local ok, err = pcall(function()
    error("뭔가 잘못됐어!")
end)
print(ok)   -- false
print(err)  -- "...: 뭔가 잘못됐어!"

-- error()로 에러 객체 전달
local ok, err = pcall(function()
    error({ code = 404, message = "찾을 수 없음" })
end)
if not ok then
    print("에러 코드: " .. err.code)
    print("메시지: " .. err.message)
end

-- xpcall: 에러 핸들러 지정
local ok, result = xpcall(
    function()
        local t = nil
        return t.value  -- nil 인덱싱 에러
    end,
    function(err)
        return "에러 발생: " .. tostring(err) ..
               "\n스택: " .. debug.traceback()
    end
)
print(result)
  • coroutine.create(fn) — 코루틴 생성 (suspended 상태)
  • coroutine.resume(co, ...) — 코루틴 실행/재개
  • coroutine.yield(...) — 실행 중단, 값 반환
  • coroutine.wrap(fn) — 함수처럼 호출 가능한 코루틴
  • pcall(fn, ...) — 보호된 호출 (ok, result 반환)
  • xpcall(fn, handler) — 에러 핸들러 포함 보호된 호출
  • error(msg, level) — 에러 발생
💡

코루틴은 OS 스레드가 아닌 협력적(cooperative) 멀티태스킹입니다. yield를 명시적으로 호출해야만 다른 코루틴에 제어권이 넘어갑니다.