본문으로 바로가기

Lua 6. 코루틴(Coroutine)

category 프로그래밍 언어Lua 10개월 전
반응형

코루틴(Coroutine)

루아에서 코루틴은 생성(Create), 재개(resume) 및 양보(yield) 세 가지 동작을 기본으로 제공한다.

루아의 다른 값과 마찬가지로 코루틴은 가비지 컬렉션에 의해 삭제된다.

생성(Create)

local co = coroutine.create(function() ... end)

function hello()
    for i = 1, 5 do
        print("Hello, " .. i)
    end
end

local hello_co = coroutine.create(hello)
  • coroutine.create 함수는 새 코루틴을 만들고 실행을 위해 별도의 스택을 할당한다.
  • 실행할 함수를 인수로 받으며 해당 코루틴에 대한 참조를 반환한다.
  • 생성 후 코루틴의 상태는 정지(Suspended) 상태에 있다.
  • 익명 함수를 인수로 전달할 수도 있다.

재개(Resume)

local status, value = coroutine.resume(hello_co)
  • coroutine.resume 함수는 코루틴을 활성화하고, 필요한 첫 번째 인수로 코루틴 참조를 받는다.
  • 코루틴이 재개되면 중지된 이후 지점부터 실행되며 정지되거나 종료될 때까지 실행된다.
  • 코루틴이 정상적으로 종료되면 coroutine.resume 함수는 실행 성공 여부와 코루틴 메인 함수에서 반환된 모든 값을 반환한다.
  • 코루틴이 한 번 종료되면 재실행 할 수 없으므로 다시 생성해서 사용해야 한다.

양보(Yield)

local co1 = coroutine.create(function()
    for i = 1, 5 do
        print("co1: " .. i)
        coroutine.yield()
    end
end)

local co2 = coroutine.create(function()
    for i = 1, 5 do
        print("co2: " .. i)
        coroutine.yield()
    end
end)

for i = 1, 5 do
    coroutine.resume(co1)
    coroutine.resume(co2)
end
  • coroutine.yield 함수를 실행하면 코루틴은 일시 중단되며 코루틴의 실행 상태가 저장된다.
  • 중단 이후 코루틴을 재개하면 코루틴이 정지된 정확한 시점부터 실행이 계속된다.

래핑(Wrap)

이 외에도 coroutine.wrap 함수가 존재한다. 해당 함수는 기존 코루틴과 달리 코루틴 생성 이후 재개 함수를 명시적으로 사용할 필요가 없으며 wrap 함수의 간단한 내부 구현은 아래와 같다.

function wrap(f)
    local co = coroutine.create(f)
    return function(v)
        status, val = coroutine.resume(co, v)
        if status then return val
        else error(val)
        end
    end
end
  • 이 보조 함수는 corutine.resume 실행 함수를 반환하며 코루틴을 간편하게 사용할 수 있도록 설계되어 있다.
local co = coroutine.wrap(
function(a)
    local c = coroutine.yield(a + 2)
    return c * 2
end)

b = co(20)
print(b)

d = co(b + 1)
print(d)

--[[
    Output:
    22
    46
]]
  • 코루틴을 생성하고 처음으로 실행하면 yield 에 의해 일시 중단되고 22 (a + 2)의 값으로 반환된다.
  • 두 번째 실행 되었을 때 로컬 변수 c 는 23 (b + 1) 값을 얻게 되고 최종적으로 46 (c * 2) 값이 출력되고 코루틴이 종료된다.

상태(Status)

local function hello()
    print("Hello, ")
    coroutine.yield()
    print("Lua")
end

local co = coroutine.create(hello)

print(coroutine.status(co)) -- suspended

coroutine.resume(co)
print(coroutine.status(co)) -- suspended

coroutine.resume(co)
print(coroutine.status(co)) -- dead
  • 코루틴의 상태에는 suspended, running, dead, normal이 있다.
  • coroutine.status 함수로 현재 코루틴의 상태를 문자열로 확인할 수 있다.
  • suspended 상태는 처음 생성되었거나 yield에 의해 일시 중단된 상태다.
  • running 상태는 현재 코루틴이 동작중인 상태이며 주로 코루틴 내부에서 확인된다.
  • dead 상태는 코루틴이 완료되어 종료된 상태다.
  • normal 상태는 코루틴이 재개되기를 기다리는 상태이며 외부에서 확인 가능하나 코루틴의 특성 때문에 확인하기 힘들다.

코루틴 사용 예시

function producer()
    for i = 1, 5 do
        coroutine.yield(i)
    end
end

function consumer(producer_co)
    while true do
        local success, value = coroutine.resume(producer_co)
        if coroutine.status(producer_co) == "suspended" then
            print("Consumed: ", value)
        else
            break;
        end
    end
end

local producer_co = coroutine.create(producer)
consumer(producer_co)