Minssuy

비동기 - 코루틴 (Coroutine)

Unity for Game Development
By Minssuy
Posted 2026/05/242026년 5월 24일 일요일 AM 12:00
4 min read703 words
비동기 - 코루틴 (Coroutine)

은행


여러분들께선 오늘 새로운 통장을 만들기 위해 차를 끌고 은행을 방문했습니다.
아뿔싸, 은행을 방문하니 손님을 응대해줄 창구가 하나밖에 없는 은행이네요.
어쩔 수 없이 조금 기다려야겠습니다.


약 1시간을 기다린 뒤, 드디어 여러분들의 차례가 되었습니다.
은행원 앞에 앉아서, 안내에 따라 통장을 만드는 절차를 진행합니다.


은행원이 도장이 필요하다고 하는데, 안타깝게도 여러분들은 깜빡하고 차에 도장을 두고 은행에 왔습니다.
“차에 도장을 두고 와서, 5분 정도만 기다려주세요!” 라고 말한 뒤, 은행 밖으로 나왔습니다.
여러분들이 도장을 가지러 차에 간 사이, 은행원은 잠시 다른 업무를 진행합니다.


동기와 비동기


손님들은 순차적으로 한 명씩 처리되고 있었기 때문에, 약 1시간 동안 아무것도 하지 못하고 대기만 했습니다.
이것을 보고 동기 라고 합니다. 앞선 일이 완료가 될 때까지 계속해서 기다리기만 해야 하는 것이지요.


겨우 여러분들의 차례가 된 후, 도장을 가지러 차에 간 동안 은행원은 잠시 밀린 다른 업무를 했습니다.
이것을 보고 비동기 라고 합니다. 통장을 만드는 업무는 잠시 대기하고, 다른 업무를 진행하는 것이지요.


여기서 중요한 점은 창구가 하나 였다는 점이고, 이것을 보고 단일 스레드, 또는 싱글 스레드 라고 부릅니다.
스레드 라는 개념은 현재는 이해하실 필요가 없으며, 잊어버리셔도 무방합니다.

하지만 창구가 하나 였다는 사실은 꼭 기억해두시길 바랍니다. 나중에 깊은 이해를 할 때 도움이 됩니다.


동기 프로그래밍


동기 프로그래밍 이라고 제목을 붙이니, 어려운 내용처럼 보이지만 두려워하실 필요 없습니다.
여러분들께서 평상시에 작성하시는 코드가 동기 입니다.

예시 코드 보겠습니다.

void Start()
{
    WaitInChair(); // 의자에서 1시간 대기
    MakeAccount(); // 은행원에게 통장 만들기 요청
}

void WaitInChair()
{
    int one_hour = 3600;

    for(int i = 0; i < one_hour; i++)
    {
        Debug.Log("1시간 기다리는중...");
    }
}

void MakeAccount()
{
    Debug.Log("통장 만들기 시작!");
}

위의 코드가 실제로 1시간을 기다리는 건 아니지만, 조금 더 와닿기 위해서 이렇게 작성해보았습니다.
Start() 내부에 작성된 함수를 보니, WaitInChair 가 완료가 된 후 MakeAccount 가 호출됩니다.


이것을 그림으로 표현해보겠습니다.

Sync 동기 프로그래밍 (Synchronous Programming)

이처럼 순차적으로 실행되는 것을 동기 프로그래밍 이라고 합니다. 여러분들이 항상 작성하시던 것들입니다.
하지만 위의 코드는 “5분만 기다려주세요!” 라고 말한 것과, 은행원이 다른 업무를 하는 내용은 없네요.


비동기 프로그래밍


이번엔 은행원의 예시 코드를 보겠습니다.

void Start()
{
    StartCoroutine(MakeAccount()); // 통장 만들기 시작
    DoOtherWork(); // 다른 업무
}

IEnumerator MakeAccount()
{
    Debug.Log("은행원 : 통장 만들기 시작!");
    Debug.Log("은행원 : 도장이 필요합니다.");
    Debug.Log("손님 : 도장 가지러 5분만 다녀올게요!");

    yield return new WaitForSeconds(5f);

    Debug.Log("은행원 : 통장 만들기 완료!");
}

void DoOtherWork()
{
    Debug.Log("은행원 : 밀린 서류 정리 중...");
}

문법을 이해하기 전, 예시코드의 결과부터 확인 해보겠습니다.

은행원 : 통장 만들기 시작!
은행원 : 도장이 필요합니다.
손님 : 도장 가지러 5분만 다녀올게요!
은행원 : 밀린 서류 정리 중...

(5초 대기 후)
은행원 : 통장 만들기 완료!

위의 코드에서 중요한 건, 손님이 “5분만 기다려주세요!” 라고 말한 순간입니다.

yield return new WaitForSeconds(5f);

이것 역시 사진으로 흐름을 확인해보겠습니다.

Async 비동기 프로그래밍 (Asynchronous Programming)

은행원은 통장 만들기 작업을 잠시 멈추고, 다음 업무 DoOtherWork 로 넘어갑니다.
5초가 지난 뒤, 다시 멈췄던 자리로 돌아와 통장 만들기를 이어서 진행합니다.


한 가지 짚고 갈 점이 있는데, Start 함수 자체는 사실 DoOtherWork 가 끝나는 순간 종료됩니다.
다만 코루틴은 별도로 Unity 엔진이 관리하고 있어서, 5초 후 멈췄던 자리에서 다시 깨어납니다. Unity 엔진이 어떻게 관리를 하고 있는지는 이 글에서 다루지 않습니다.

다음은 문법을 살펴보겠습니다.


코루틴 (Coroutine)


컴퓨터 용어는 추상적인 말들이 많아서 이해하는 데 어려움이 많습니다.
이럴 땐 단어의 뜻부터 알아보는 것이 개념을 이해하는 데 큰 도움이 됩니다.

코루틴이란, 함께라는 뜻인 co- 라는 접두사와, 규칙적으로 하는 일이라는 단어인 routine 이 합쳐진 단어입니다. 굳이 직역해보자면 함께하는 규칙적인 일 인데, 어떤 식으로 함께하는지 확인해보겠습니다.


Unity 에서 코루틴을 쓰기 위해선 세 가지만 기억하시면 됩니다.

  • 반환 타입 : IEnumerator
  • 멈출 지점 : yield return
  • 함수 호출 : StartCoroutine()

하나씩 보겠습니다.


IEnumerator


일반적인 함수는 아래와 같이 작성할 수 있습니다.

void MakeAccount()
{
    Debug.Log("통장 만들기 시작!");
}

위 함수는 반환 타입이 void 인 형태입니다. 그렇기에 return 반환값이 없는 모습입니다.


이번에는 코루틴 함수를 보겠습니다.

IEnumerator MakeAccount()
{
    Debug.Log("통장 만들기 시작!");
    yield return new WaitForSeconds(5f);
    Debug.Log("통장 만들기 완료!");
}

코루틴 함수의 반환 타입은 IEnumerator 여야 합니다.
또한 함수 안에서는 일반적인 return 이 아닌, yield return 으로 값을 반환해야 합니다.


yield return


yield 의 뜻은 양보하다 라는 의미입니다. 단어의 뜻이 조금은 와닿으신가요?
원래 함수는 끝날 때까지 호출자(caller)에게 제어권을 돌려주지 않지만, 잠시 양보(yield)함으로써 co-routine 하게 됩니다.


반환값인 yield return 뒤에 무엇을 적느냐에 따라 양보의 길이가 달라집니다.
대표적으로 많이 쓰이는 예시는 아래와 같습니다.

yield return null; // 다음 프레임에 재개
yield return new WaitForSeconds(5f); // 5초 대기 (timescale 영향 O)
yield return new WaitForSecondsRealtime(5f); // 5초 대기 (timescale 영향 x)
yield return new WaitUntil(() => isTrue); // 조건이 true 될 때까지 대기

이 외에도 종류가 더 있지만, 처음엔 위 네 가지 정도만 알아도 충분하며 나머지는 필요할 때 찾아보시면 됩니다.


StartCoroutine


일반적인 함수의 호출은 아래와 같이 이루어집니다.

MakeAccount();

이번에는 코루틴 함수를 호출하는 모습을 보겠습니다.

StartCoroutine(MakeAccount());

그럼 만약, 코루틴 함수를 일반 함수처럼 호출하면 어떻게 될까요?

void Start()
{
    MakeAccount(); // not StartCoroutine
}

IEnumerator MakeAccount()
{
    Debug.Log("통장 만들기 시작!");
    yield return new WaitForSeconds(5f); 
    Debug.Log("통장 만들기 완료!");
}

정답은, 아무런 에러가 발생하지 않으며 함수 안의 코드가 한 줄도 실행되지 않습니다.
콘솔에 아무런 로그가 찍히지 않기 때문에, 코루틴 함수는 반드시 StartCoroutine 으로 실행시켜줘야 합니다.


코루틴 함수도 함수이기 때문에, 파라미터를 넣을 수 있습니다.

void Start()
{
    StartCoroutine(MakeAccount("Minssuy", 100));
}

IEnumerator MakeAccount(string name, int money)
{
    Debug.Log($"{name} 손님 : {money}만원 통장 만들기 시작!");
    yield return new WaitForSeconds(5f); 
    Debug.Log($"{name} 손님 : 통장 만들기 완료!");
}
Minssuy 손님 : 100만원 통장 만들기 시작!
(5초 대기 후)

Minssuy 손님 : 통장 만들기 완료!

StopCoroutine


통장을 만드는 도중, 손님이 갑자기 “안 만들고 싶어졌어요!” 라고 할 수도 있습니다.
은행원은 진행 중이던 업무를 멈춰야 합니다. 코루틴도 마찬가지로, 도중에 멈출 수 있습니다.


코루틴을 멈추기 위해선, 사전 준비가 필요합니다.

Coroutine accountCoroutine;

void Start()
{
    accountCoroutine = StartCoroutine(MakeAccount());
}

StartCoroutine 은 사실 반환값이 존재하는데, Coroutine 타입의 객체입니다.
이 객체를 받아두면, 나중에 그 코루틴을 다시 참조할 수 있게 됩니다. 이것을 멈춰보겠습니다.

Coroutine accountCoroutine;
bool feelings = true;

void Start()
{
    accountCoroutine = StartCoroutine(MakeAccount());
}

void Update()
{
    if(!feelings)
    {
        CancelAccount();
    }
}

void CancelAccount()
{
    StopCoroutine(accountCoroutine);
    Debug.Log("손님 : 만들기 싫어요!");
}

이 외에도 StopAllCoroutines 로 현재 객체의 모든 코루틴을 한 번에 멈추는 방법도 있습니다.
이것 또한 필요할 때 사용방법을 찾아보시면 되겠습니다.


마치며


이 글에선 비동기에 대한 개념과 코루틴 사용법을 간단히 알아보았습니다.
하지만 이 글에선 의문이 남는 부분이 조금 많은데, 제가 생각하기엔 이러한 의문이 남습니다.

  • IEnumerator 의 정체가 무엇이길래, 함수를 잠시 멈춰둘 수 있을까?
  • yield return 다음 줄로 돌아왔을 때, 함수의 진행 상태를 어떻게 그대로 기억하고 있을까?
  • Unity 엔진은 코루틴을 어떻게 관리하고 있을까?

뿐만 아니라 이 글은 코루틴의 이해에 중점을 둔 글이므로, 개념에 조금의 오류가 있습니다.
다음 글에선 이런 마법같은 일이 어떻게 일어나는지, 그리고 코루틴의 정체에 대해 깊게 파헤쳐보겠습니다.


Reference


© Powered by Minssuy