Unity에서 코루틴은 실행을 일시 중지하고 Unity에 제어권을 반환하지만 다음 프레임에서 중단된 부분부터 실행할 수 있는 메서드로 시간에 따른 절차적 애니메이션이나 이벤트를 포함하기 위해 메서드 호출을 사용하려는 상황에서 사용할 수 있다.
코루틴은 스레드가 아니다. 코루틴 내에서 실행되는 동기 작업은 여전히 메인 스레드에서 실행되며, 메인 스레드에 소요되는 CPU 시간을 줄이려면 다른 스크립트 코드와 마찬가지로 코루틴의 작업 차단을 방지하는 것이 중요하다.
HTTP 전송, 에셋 로드, 파일 I/O 완료 등을 기다리는 것과 같이 긴 비동기 작업을 처리해야 하는 경우 코루틴을 사용하는 것이 가장 좋다.
코루틴은 System.Collections 네임스페이스를 사용 선언하고, IEnumerator 반환 타입과 본문의 yield 반환문으로 선언한다.
using System.Collections;
using UnityEngine;
public class exampleClass : MonoBehaviour
{
IEnumerator TestCoroutine()
{
// 코루틴 시작
Debug.Log($"[{Time.time:F2}초] 코루틴 실행");
// 한 프레임 대기
yield return null;
// 한 프레임 후 실행
Debug.Log($"[{Time.time:F2}초] 코루틴 이어서 실행");
}
}
yield 반환문 라인은 실행이 일시 정지되고 다음 프레임에서 다시 시작되는 지점이다.
선언한 코루틴을 실행하려면 StartCoroutine 메서드를 사용한다.
using System.Collections;
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
void Start()
{
// 메서드 형태로 사용하는 방법
StartCoroutine(TestCoroutine());
// 또는
// 문자열 형태로 사용하는 방법
StartCoroutine("TestCoroutine");
}
IEnumerator TestCoroutine()
{
// 코루틴 시작
Debug.Log($"[{Time.time:F2}초] 코루틴 실행");
// 한 프레임 대기
yield return null;
// 한 프레임 후 실행
Debug.Log($"[{Time.time:F2}초] 코루틴 이어서 실행");
}
}
대부분은 경우 메서드 형태로 사용하지만 문자열 형태로 사용하면 코루틴 메서드를 동적으로 선택할 수 있는 유연성이 제공된다.
문자열 형태로 사용하는 단점은 더 높은 런타임 오버헤드를 가지며 하나의 매개변수만 전달 할 수 있다는 것이다.
기본적으로 Unity는 yield 반환문 이후 한 프레임 후에 코루틴을 재개하는데, 만약 시간을 지연 시키고 싶다면 WaitForSeconds를 사용할 수 있다.
using System.Collections;
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
void Start()
{
StartCoroutine(TestCoroutine());
}
IEnumerator TestCoroutine()
{
// 코루틴 시작
Debug.Log($"[{Time.time:F2}초] 코루틴 실행");
// 1초 대기
yield return new WaitForSeconds(1f);
// 1초 후 실행
Debug.Log($"[{Time.time:F2}초] 코루틴 이어서 실행");
}
}
참고: MonoBehaviour의 enabled를 false로 설정하여 비활성화한 경우 Unity는 코루틴을 중지하지 않는다.
using System.Collections;
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
private Coroutine coroutine;
void Start()
{
// 코루틴 실행
coroutine = StartCoroutine(TestCoroutine());
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// 코루틴 중지
StopCoroutine(coroutine);
Debug.Log("코루틴 중지");
}
}
IEnumerator TestCoroutine()
{
// 코루틴 시작
Debug.Log($"[{Time.time:F2}초] 코루틴 실행");
while (true)
{
// 1초 대기
yield return new WaitForSeconds(1f);
// 1초 후 실행
Debug.Log($"[{Time.time:F2}초] 코루틴 이어서 실행");
}
}
}
using System.Collections;
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
void Start()
{
// 코루틴 실행
StartCoroutine(CoroutineA());
StartCoroutine(CoroutineB());
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// 코루틴 중지
StopAllCoroutines();
Debug.Log("모든 코루틴 중지");
}
}
IEnumerator CoroutineA()
{
// 코루틴 시작
Debug.Log($"[{Time.time:F2}초] 코루틴A 실행");
while (true)
{
// 1초 대기
yield return new WaitForSeconds(1f);
// 1초 후 실행
Debug.Log($"[{Time.time:F2}초] 코루틴A 이어서 실행");
}
}
IEnumerator CoroutineB()
{
// 코루틴 시작
Debug.Log($"[{Time.time:F2}초] 코루틴B 실행");
while (true)
{
// 2초 대기
yield return new WaitForSeconds(2f);
// 2초 후 실행
Debug.Log($"[{Time.time:F2}초] 코루틴B 이어서 실행");
}
}
}