내일배움캠프 56일차 TIL, 코루틴

황오영·2024년 7월 16일
0

TIL

목록 보기
56/56
post-thumbnail

코루틴

코루틴이란?

  • 공식문서에서 정리하길 대부분의 경우 메서드를 호출하면 실행을 완료한 뒤 호출한 메서드에 제어와 선택적 반환 값을 반환하므로 메서드 내에서 발생한 모든 행동은 단일 프레임 업데이트 내에서 발생한다.
  • 하지만 모든 메서드를 이런식으로 한번에 처리할 수 없는 상황이 있기에 코루틴을 통해 작업을 다수의 프레임에 분산하여 실행을 할 수 있다. 코루틴은 작업을 '일시 정지하고 제어를 유니티에 반환'하지만 중단한 부분에서 다음 프레임을 계속할 수 있는 메서드 로 정의한다.
  • 여기서 중요한 포인트는 제어를 유니티에 반환 이라는 키워드이다. 자세한건 뒤쪽에서 좀 더 정리

코루틴의 특징

  • IEnuemrator를 반환한다. IEnuemrator는 열거자 인터페이스인데 작업을 분할하여 수행하는 함수라고 생각하면 좋다.
  • yield return을 만나는 순간 마다 다음 구문이 실행되는 프레임으로 구분된다.
  • yeild break를 만나면 바로 코루틴이 종료된다.
  • MonoBehaviour 를 상속받는 객체가 있어야하고 이를 상속받는 클래스에서만 구현되어 있어야 한다.
  • 코루틴에는 소유권이라는 개념이 있는데 소유권을 가진 객체가 비활성화되거나 파괴되면 코루틴이 중단된다. 그래서 비활성화된 객체에 코루틴 시작을 요청하면 작동되지 않는다.
  • 코루틴은 메인스레드에서 실행된다. 절대 멀티 스레드로 되지않는다.

메소드

  • StartCoroutine() : 실행시켜주는 메소드, 이 메소드를 호출한 객체가 실해된 코루틴의 소유권을 가짐
  • StopCoroutine() : 실행을 종료해주는 메서드, 소유권을 가진 코루틴 중 일치하는 코루틴을 종류
  • StopAllCoroutines() : 현재 소유권을 가진 모든 코루틴을 종료시킨다.
  • YieldInstruction클래스 코루틴을 대기시키는데 사용되는 클래스
IEnumerator Co_Test()
{
    // 다음 FixedUpdate 호출 시 까지 대기합니다.
    yield return new WaitForFixedupdate();

    // 다음 Update 호출 시 까지 대기합니다.
    yield return null;

    // time만큼의 시간(초)이 지난 후 첫 프레임까지 대기합니다.
    yield return new WaitForSeconds(float time);

    // time만큼의 시간(초)이 지난 후 첫 프레임까지 대기합니다.
    // TimeScale의 영향을 받지 않습니다.
    yield return new WaitForSecondsRealtime(float time);

    // 모든 렌더링 작업이 완료되어 프레임이 끝날 때까지 대기합니다.
    yield return new WaitForEndOfFrame();
}

코루틴의 작동 원리

  • C#에서 제공되는 반복자를 활용하여 코루틴을 만들었는데 배열과 같은 컬렉션을 단계적으로 순회하기 위해 만들어진 개념이 반복자인데 유니티에선 한 프레임에 반복이 끝나는 것보다 단계가 진행될 때마다 다음 프레임에서 실행되도록 하는 방식을 채택하면서 현재의 코루틴이 만들어지게 되었다.
  • 중요한 것은 코루틴의 소유권의 개념인데 프레임과 소유권은 DelayedCallManager 클래스에서 관리가 된다. yield return 구문을 만나게 되면 현재 실행중인 코루틴이 등록되면서 DelayedCallManager에서 다음 프레임부터 코루틴이 실행되는 방식이다.
  • 여기서 코드 하나를 보자
void PrintLog()
{
    Debug.Log("Start PrintLog");

    StartCoroutine(Co_PrintLog());

    Debug.Log("End PrintLog");
}

IEnumerator Co_PrintLog()
{
    Debug.Log("10");
    yield return null;

    Debug.Log("20");
    yield return null;

    Debug.Log("30");
}

해당 코드의 콘솔창에 찍히는 로그의순서는 어떻게될까?
결과는

// PrintLog 메서드가 호출되는 시점에 따라 시작 Frame이 1이 아닐 수 있습니다.
// [Frame 1] Start PringLog
// [Frame 1] 10
// [Frame 1] End PringLog
// [Frame 2] 20
// [Frame 3] 30

이런식으로 나오게 되는데 PrintLog는 일반 메소드이므로 한 프레임에 전부 처리가 되어야한다. 그래서 모든 프레임이 한번에 다 나오게 되고 코루틴의 yield return null을 만나는 순간부터 다음 프레임에 호출되기 때문에 코루틴함수는 다음 프레임부터 돌게 되는것이다.

StopCoroutine에 관하여

  • 코루틴을 멈추는 함수인 Stop코루틴과 Start코루틴은 매개변수를 맞춰서 써야한다는것
  • string은 string끼리 써야한다는것.. 이러지않으면 등록된 코루틴의 소유권이 달라 제대로 중지가 되지않는다.

WaitForSeconds

  • WaitForSeconds를 사용하면 파라미터를 넘긴 시간이 정확하게 흐르기 전까지 아무 연산을 하는것이 아니라 해당 조건이 충족될 때까지 프레임마다 연산을 수행하고 조건을 다시 검사하는것이다. 그래서 이런 대기시간에서 프레임에서 거의 반드시 오차가 발생하게 되는것 정확한 시간에 바로 실행되지 않으므로 주의하자
  • new WaitForSeconds의 클래스의 경우 가바지가 많이 쌓이므로 만약 자주 반복되는 코드라면 캐싱을 해서 사용하는것이 가비지 콜렉터 관리면에서도 좋다.

오늘의 회고

  • 생각보다 코루틴을 많이 몰랐던것 같아서 이번 기술면접 대비하면서 많은것을 배워서 재미있는 시간이었다. 추후 코루틴을 쓸 일이 있다면 좀 더 잘 쓸수 있을것같다!
  • 최종프로젝트에 에드레서블 에셋을 쓰려고 준비중인데 생각보다 할게많고 처리할게 많아서 애먹고 있다... 좀 더 열심히해서 잘 시스템을 구축해놔야지 그러면 나중에 다른 프로젝트 할때에도 편할것같다.
  • 기술면접도하고... 포트폴리오도 해야되서 이번주는 바쁜 한주가 될것같다. 드디어 포트폴리오를 만들다니.. 예전에 만든건 너무 아쉬워서 좀 더 보완 잘해서 멋잇는 포트폴리오로 만들어야지!
profile
게임개발을 꿈꾸는 개발자

0개의 댓글