Unity3D/유니티 공부

[Unity / C#] 코루틴(Coroutine)

상연 2022. 4. 27. 04:38

목차

    코루틴(Coroutine)

     

    Coroutine 코루틴의 사용이유

    일반적으로 유니티에서 함수를 호출하면 값을 반환하기 전에 실행이 완료되어버린다.

    즉, 함수에서 수행되는 모든 Action이 하나의 Frame에서 발생하고 그친다는것이다.

    그렇기 때문에 Update() 같이 프레임간격으로 실행되는 함수안에서 실행하지 않고 단일 호출로 함수를 실행하게 되면?

    그 함수는 아마 우리가 기대한 효과를 가질 수 없을것이다.

    void Fade() 
    {
        for (float f = 1f; f >= 0; f -= 0.1f) 
        {
            Color c = renderer.material.color;
            c.a = f;
            renderer.material.color = c;
        }
    }

    위의 코드가 그 예시와 같다.

    alpha값을 점진적으로 줄이고 싶은 의도가 다분해보이지만 

    실상 함수를 실행하게 되면 점진적으로 줄어드는 중간과정없이 함수가 실행된 오브젝트는 단숨에 투명해질것이다.

    하나의 프레임 업데이트에서 전체적으로 실행이 되어버렸기 때문이다.

     

    그렇다면 어떻게 해야할까? 원하는 효과를 내기 위해서는 Update()에 추가해야할까?

    물론 불가능한것은 아니며, 어쩌면 이는 괜찮은 방법이 될 수 도 있을것이다.

    하지만, 비슷한 효과를 다른 버전으로 10개 20개 수십개를 만들어야 한다고 가정하면 그 모든것을 update문에 넣고 조건문으로 처리를 한다는것은 유지보수측면이나 여러 관점에서 말도 안되는 일이 될 것이다.

    따라서 이러한 경우에는 Coroutine을 사용하면 편리하다.

    IEnumerator Fade() {
        for (float f = 1f; f >= 0; f -= 0.1f) {
            Color c = renderer.material.color;
            c.a = f;
            renderer.material.color = c;
            yield return null;
        }
    }

    코루틴은 이와 같이 IEnumerator을 반환값으로 가지며 yield로 구성되어있다.

    yield return 에 조금 주목을 할 필요가 있는데, 이를 통해서 현재 위치를 기억을 하고 다른 루틴에게 수행권한을 넘겨서 여러개의 쓰레드가 마치 동시에 동작하는것과 같은 효과를 제공하게 된다.

    이 부분에 대해서는 아래의 블로그에서 굉장히 상세히 설명되어있어. 참고하면 좋을 듯 하다.

     

     

    Unity C# – Coroutine 알아보기 | 아이군의 블로그

    유니티에서 사용되는 코루틴(Coroutine)은 왜 필요한가? 유니티에서 화면의 변화를 일으키기 위해서는 Update() 함수 내에서 작업을 하게 됩니다. 이 Update() 함수는 매 프레임을 그릴때마다 호출되며

    theeye.pe.kr

     

    여러개의 쓰레드가 마치 동시에 동작하는것과 같아 보인다.

    우리는 이 말에 조금 더 관심을 가져야 한다. 왜냐하면 유니티는 한 번에 하나의 작업만 처리하는 단일 스레드 방식을 사용하기 때문이다.

    이렇듯 위와같은 순서로 이벤트 함수를 사용한다, Update함수같은 경우에는 반복해서 그 부분이 사용된다고 보면된다.

    그리고 Coroutine의 경우에는 보면 알겠지만 Game Logic Layer에 위치하여 Update와 함께 yield를 사용하여 루틴을 번갈아가며 실행한다고 생각하면 된다.

    따라서 이 yield를 반환하는 시점, 양보하는 시점을 프로그래머가 조율할 수 있기때문에

    원하는 타이밍에 맞추어 코드를 실행하고 종료할 수 있다는것에서 큰 장점을 갖는다.

    또한 원하는 Coroutine을 키고 끌 수 있는 함수를 지원하기에 필요한것만 실행 / 중지 할 수있다.

    • 여러 루틴을 yield를 통해 번갈아 가며 실행 가능하다
    • 특정 조건에 맞춰 실행하는, 유연한 프로그래밍이 가능하다
    • 쓰레드가 아니며, 비동기 즉 동시에 실행되지 않는다

    장점은 이렇게 볼 수 있는데 그렇다면 Coroutine의 단점으로는 무엇이 있을까?

     

    Coroutine 코루틴의 단점

    크게 두 가지로 볼 수있다.

    첫 번째는 사실 단점이라고 하면 단점이고 아니라면 아니라고 할 수도 있겠지만

    1. 오브젝트가 비활성화 되면 코루틴은 정지한다.

    단, 오브젝트는 활성화 되어있고 스크립트만 비활성화 되어있으면 코루틴은 유지된다.

    이 부분에 대해서는 추후 Invoke와의 차이점에서 조금 더 상세히 다룰 예정이다.

     

    2. Garbage를 많이 생성한다.

    코루틴을 시작하기 위한 StartCoroutine() 메서드는 이 코루틴을 관리하기 위해 인스턴트가 생성된다. 

    여기서도 가비지가 생성이 되지만 이는 유니티 자체 엔진의 문제이고 통상보다 많은 가비지를 생성한다고 해서 우리가 크게 조치할 수있는 부분은없다.

    다만, 되도록 불필요한 StartCoroutine()을 자제해야한다.

    그리고 yield를 할때 보통 

    yield new WaitforSeconds()

    이렇게 new 를 통해 인스턴트를 생성해서 하게 되는데 이 부분에서 가비지를 생성하게 된다.

    다행이도, 이 부분에 있어서 캐싱을 하면 가비지를 방지할 수 있다.

    코루틴 가비지 최적화

     

    유니티 코루틴 최적화

    YieldInstruction을 캐싱해서 코루틴에서 사용하는 yield 구문을 최적화하자

    ejonghyuck.github.io

    캐싱 방법에 대해서는 위의 글이 굉장히 좋아 첨부한다.