* 본 글에서 다루는 Coroutine은 Unity에서 사용되는 Coroutine에 대한 정보 위주로 작성되었습니다.
1. Coroutine
Coroutine은 Unity에서 시간을 기반으로 작업을 처리해야할 때 사용되는 기능입니다. 특정 작업을 한 프레임 단위로 끝내지 않고 여러 프레임에 걸쳐서 실행할 수 있도록 도움을 줍니다.
Coroutine을 사용하면 함수를 잠시 중단했다가 이후 특정 시점에서 이어서 진행할 수 있기 때문에 대기 시간을 두어 시간 지연을 주거나 반복되는 작업을 효율적으로 처리할 수 있습니다.
2. 사용 방법
1) 전체 스크립트
using System.Collections;
using UnityEngine;
public class Coroutine : MonoBehaviour
{
void Start()
{
StartCoroutine(CoroutineSample());
}
IEnumerator CoroutineSample()
{
Debug.Log("코루틴 시작 시점");
yield return new WaitForSeconds(2f);
Debug.Log("2초 경과");
yield return new WaitForSeconds(1f);
Debug.Log("1초 추가 경과, 총 3초 경과");
}
}
2) 코드 상세 설명
using System.Collections;
IEnumerator를 사용하기 위한 네임스페이스 선언입니다.
* IEnumerator란 C#의 Iterator(반복자) 인터페이스로 Unity에서는 IEnumerator를 사용하여 Coroutine을 구현할 수 있습니다.
StartCoroutine(CoroutineSample());
IEnumerator를 반환하는 Coroutine 함수를 실행합니다.
StartCoroutine()으로 실행시킨 Coroutine을 종료하는 방법은 2가지가 있습니다.
StopCoroutine(CoroutineSample);
StopAllCoroutines();
이름에서 직관적으로 보이듯이 StopCoroutine()은 하나의 Coroutine을 종료하고 StopAllCoroutines()는 실행 중인 모든 Coroutine들을 종료합니다.
IEnumerator CoroutineSample()
StartCoroutine()으로 호출하여 실행하기 위해선 함수가 IEnumerator를 반환하도록 작성해야 합니다.
yield return new WaitForSeconds(2f);
yield return은 IEnumerator에서 사용되며 후에 기술되는 조건에 충족했을 때 함수를 이어서 진행하게끔 동작하는 구문입니다. 대기하는 동안 함수는 상태를 그대로 유지합니다.
3) 출력 결과
* yield return의 다양한 사용법
사용법 | 설명 |
yield return null; | 다음 프레임까지 대기, 조건 없이 대기합니다. |
yield return new WaitForSeconds(1.0f); | 지정한 시간(초 단위) 대기, 게임 시간에 영향 |
yield return new WaitForRealSeconds(1.0f); | 지정한 시간(초 단위) 대기, 실제 시간에 영향 |
yield return new WaitForUntill(i == 1); | 특정 조건이 참이 될 때 까지 대기 |
yield return new WaitWhile(i == 1); | 특정 조건이 거짓이 될 때 까지 대기 |
yield return new WaitForEndOfFrame(); | 현재 프레임이 끝날 때 까지 대기 |
yield return new WaitForFixedUpdate(); | 다음 FixedUpdate()까지 대기 (Unity Life Cycle) |
yield return의 사용법에 대해 찾아보면 위처럼 다양한 사용법들이 존재하는데, 저는 아직 WaitForSeconds(), WaitForRealSeconds(), WaitForFixedUpdate() 이 3가지만 사용해본 것 같습니다.
WaitForSeconds()와 WaitForRealSeconds()는 시간을 기준으로 대기한다는 공통점이 있지만 이 둘의 시간을 체크하는 방식이 다릅니다.
비교 항목 | WaitForSeconds() | WaitForRealSeconds() |
Time.timeScale의 영향 | Time.timeScale 수치에 따라 느려지거나 빨라집니다. | 영향 없이 항상 동일 |
일시정지 여부 | Time.timeScale = 0 으로 게임이 멈추면 Coroutine도 일시정지 합니다. | 정지하지 않고 시간이 동일하게 흐르고 있습니다. |
프레임의 영향 | 프레임에 영향을 받습니다. ⭕ | 프레임에 영향을 받지 않습니다. ❌ |
* 조금 더 효율적으로 사용하는 방법 (자주 사용되는 Coroutine의 경우)
using System.Collections;
using UnityEngine;
public class Coroutine : MonoBehaviour
{
private IEnumerator coroutineSample;
void Start()
{
coroutineSample = CoroutineSample();
StartCoroutine(coroutineSample);
}
IEnumerator CoroutineSample()
{
while (true)
{
Debug.Log("코루틴 실행 중");
yield return new WaitForSeconds(1f);
}
}
}
StartCoroutine()으로 IEnumerator를 직접 호출하는 경우 호출될 때 마다 매번 IEnumerator 객체가 생성되기 때문에 메모리에 낭비가 생길 수 있습니다. 자주 호출되는 Coroutine의 경우 IEnumerator에 미리 대입 시켜둔 상태로 호출하는 것이 더 효율적입니다.
* 한 번 호출되고 말 Coroutine의 경우 굳이 미리 선언해줄 필요는 없습니다.
3. Async / Await와 비교 (비동기 프로그래밍)
Unity에서 비동기 처리를 한다고 하면 보통 Coroutine과 Async / Await 방식을 사용할 것입니다. 이 두 가지 방식의 차이점을 알아보도록 하겠습니다.
비교 항목 | Coroutine | Async/Await |
실행 방식 (기반) | Frame | Thread |
대기 키워드 | yield return | async, await, Task |
Unity와 연계 효율 (WaitForSecoreds 사용 여부) | ⭕ | ❌ (프레임과 무관) |
네트워크 요청 | ❌ (지원하지 않는 기능) | ⭕ (Task로 요청 가능) |
동시 실행 관리 (병렬 처리) | ❌ (어려움) | ⭕ (Task.WhenAll로 쉽게 가능) |
가장 큰 차이는 Coroutine은 유니티 엔진의 프레임과 동기화가 되어있기 때문에 WaitForSeconds를 사용할 수 있는 반면 Async/Await는 유니티 엔진의 프레임과는 별도로 동작하기 때문에 WaitForSeconds를 사용할 수 없고, 대신 반대로 Async/Await는 유니티의 환경에 구애받지 않고 정확한 비동기 프로그래밍을 구현할 수 있습니다.
* 이러한 차이점들로 인해 보통 Coroutine은 유니티 내부에서 애니메이션이나 캐릭터, UI의 이동 등 프레임 기반 로직에 많이 사용되고 Async/Await의 경우 실제 비동기 동작을 필요로 하는 네트워크 요청, 파일 입출력 등에 사용됩니다.
4. 중요한 점 정리
- WaitForSeconds()와 WaitForRealSeconds()는 시간을 기준으로 대기한다는 공통점이 있지만 WaitForSeconds()는 게임 시간을 기반으로 WaitForRealSeconds()는 현실 시간을 기반으로 시간의 흐름을 체크합니다.
- 자주 호출되는 Coroutine의 경우 IEnumerator에 미리 대입 시켜둔 상태로 호출하는 것이 더 효율적입니다.
- Coroutine은 유니티 엔진의 프레임을 기반으로 대기하고 Async/Await는 유니티 엔진의 프레임에 구애받지 않고 별도로 대기합니다.
'공부 정리 > Unity' 카테고리의 다른 글
Synchronous(동기), Asynchronous(비동기), Parallel(병렬) 비교 (2) | 2025.03.20 |
---|---|
UnityWebRequest를 활용하여 WebAPI와 HTTP 통신 (2) | 2025.03.19 |