본문 바로가기
Unity

[Unity] 코루틴(Coroutine)과 Invoke

by 적용1 2024. 11. 19.
728x90

코루틴(Coroutine)

  • 원래 유니티에서 메서드는 호출하면 단일 프레임 내에서 실행되고 완료된다.

  • 하지만 코루틴은 한 작업을 다수의 프레임에 분산시킬 수 있다. 즉, 여러 프레임 동안 실행시킬 수 있다.

  • 쉽게 말해, 코루틴은 여러 개의 루틴이 동시에 실행되게 해주며, 싱글 스레드 기반의 유니티에서 멀티스레드처럼 보이도록 병렬적인 구조를 만드는 기능이다.

    따라서 멀티스레드의 문제점인 race condition과 동기화 관련 문제를 고려하지 않아도 된다.

  • 모든 코루틴은 MonoBehaviour을 상속하는 객체들로 인해 실행되고, 그 객체들에게 코루틴의 소유권이 있다고 표현한다.

    따라서 MonoBehaviour 메서드인 StartCoroutine, StopCoroutine 등으로 실행과 정지를 시킨다.

  • 이 소유권을 가진 객체들이 비활성화(inactive)되거나 파괴될 경우, 코루틴이 같이 정지한다.

  • 매개변수 전달이 가능한 IEnumerator를 반환하는 함수로 정의된다.

    IEnumerator는 다른 언어의 iterator와 비슷한 역할을 하는 열거자이다.

    IEnumerator은 다음과 같이 선언되는데, 
    public interface IEnumerator
    {
        object Current { get; }
        bool MoveNext();
        void Reset();
    }
    열거자의 현재 위치가 저장되는 Current, 다음으로 이동하는 MoveNext 메서드가 존재한다.
  • 코루틴을 사용할 때는 yield return을 해주어야 하는데, 이를 통해서 현재 위치를 기억하고 다른 루틴에게 수행 권한을 넘겨주고 다시 와서 처리하는 방식이다.

    yield return 문이 컴파일시 코드의 위치를 저장하는 상태 머신으로 변환되고, YieldInstruction(null, WaitForSeconds 등)을 실행하고, 다음으로 이동하는 MoveNext를 다시 호출한다.

    즉, 코루틴은 MoveNext 문이 실행되고, Current인 yield return 문이 실행되고, 다시 MoveNext 문을 실행되는 것을 반복하는 것과 같다.

  • 결론적으로, 코루틴은 열거자를 이용하여 여러 프레임에서 호출되는 듯한 효과를 발휘하는 메서드이다.

    멀티스레드는 절대 아니고, 다른 메서드와 같이 메인 스레드에서 동작하므로 무한 루프나 오래 실행하는 작업에 주의해야 한다.

Invoke

  •  Invoke는 특정 함수 호출을 일정 시간 지연 후에 실행하거나, 주기적으로 반복 실행하는 기능을 제공한다.
  • 다음과 같이 메서드의 이름과 지연 시간등을 매개변수로 전달하여 실행하게 되는데,
Invoke("메서드이름(string)", 지연시간(float));


이 과정에서 리플렉션(Reflection)을 통해 메서드를 동적으로 호출하기 때문에 코루틴보다 느린 속도를 가지게 된다.

코루틴이 메서드 자체를 인자로 받아가는 것과 달리, Invoke는 메서드의 이름 문자열을 통해 런타임에 메서드를 탐색하고 실행하는 과정에서 오버헤드가 발생하기 때문이다.

 

  • InvokeRepeating을 통해 메서드를 지속 반복시킬 수도 있다.
InvokeRepeating("메서드이름(string)", 지연시간(float), 반복간격(float));

 

  • CancelInvoke 또는 오브젝트를 파괴하여 종료해주어야 한다.

  • 코루틴과 달리, 오브젝트가 inactive 상태로 바뀌어도 invoke는 멈추지 않는다.

결론

특징 Coroutine Invoke
GameObject 활성화 상태 GameObject가 비활성화되면 자동으로 멈춤, Enable되어도 재개되지 않음 GameObject 비활성화 상태와 관계없이 작동
동작 방식 Unity의 MonoBehaviour에서 관리하며 직접 스케줄링 Reflection을 통해 메서드 이름을 동적으로 호출
성능 비교적 효율적(많은 코루틴 동시 실행 시 부담될 수 있음) Reflectino 오버헤드로 인해 상대적으로 느릴 수 있음
유지보수성 타입 안정성(Type Safety)을 보장
(IEnumerator 기반)
메서드 이름을 문자열로 지정하기 때문에 오타 시 컴파일 오류
메모리 관리 GameObject가 Destroy되면 자동으로 정리 모든 Invoke는 CancelInvoke를 호출해야 정리됨
728x90

'Unity' 카테고리의 다른 글

[Unity] MonoBehaviour란  (1) 2024.11.19
[Unity] 유니티 생명 주기 함수  (0) 2024.11.02