본문 바로가기
Study/개념 정리

[Study] 코루틴

by chobbo 2024. 7. 16.

코루틴이란?

동작 원리

- 코드 내에서 구문 실행 도중 처리를 대기시키거나, 함수를 병렬로 동시에 처리할 수 있도록 한다.

- yield return을 호출하여 특정 시점까지 대기가 가능하다.

더보기

yield return null : 다음 프레임에 실행을 재개한다.
yield return new WaitForSeconds : 지정된 시간 후에 재개한다.
yield return new WaitForSecondsRealtime :  Time.timescale 값에 영향을 받지 않고 지정된 시간 후에 재개한다. 
yield return new WaitForFixedUpdate : 모든 스크립트에서 모든 FixedUpdate가 호출된 후에 재개한다.
yield return new WaitForEndOfFrame : 모든 카메라와 GUI가 렌더링을 완료하고, 스크린에 프레임을 표시하기 전에 호출된다. 
yield return StartCoroutine() : 코루틴을 연결하고 코루틴이 완료된 후에 재개한다.

- StartCoroutine()으로 실행 가능하며, Coroutine이라는 변수를 선언해 실행한 코루틴을 담을 수 있다.

Coroutine coroutine = StartCoroutine("함수 이름"); // 매개변수 하나까지만 전달 가능
Coroutine coroutine = StartCoroutine(함수()); // 성능적 이점 볼 수 있음

 

 

공식 홈페이지 생명주기


- Coroutine은 Game Logic Layer에 위치하며 Update와 함께 yield를 사용하여 루틴을 번갈아가며 실행한다. 이 yield를 반환, 즉 양보하는 시점을 프로그래머가 조율할 수 있기 때문에 원하는 타이밍에 맞추어 코드를 실행하고 종료할 수 있다.
- Ienumerator 관련 공부하기

 

Unity 코루틴(Coroutine) 이해하기: 동작원리 및 구현

Unity 코루틴이란? 무의식적으로 코루틴은 쓰레드가 생성되는 멀티스레드 방식으로 느껴질 수 있다. 하지만 코루틴은 싱글 스레드로 비동기 방식을 구현한다. 따라서 실제로 병렬 처리가 아니다.

planek.tistory.com

 

 

 

사용 예시

특정 간격으로 반복적으로 작업을 수행할 때,

스킬 쿨타임 돌릴 때 등

 

 

 

 

 

Invoke와 코루틴의 차이

코루틴

- 매개변수 전달 O

- GameObject가 비활성화 되면 동작을 멈춘다. 다시 활성화 되더라도 실행되지 않는다

- 프레임 단위로 실행을 일시정지, 시작할 수 있고 시간 초 뿐 아니라 다양한 조건을 넣어 복잡한 처리를 할 수 있다.

 

Invoke

- 매개변수 전달 X

- GameObject가 비활성화 되더라도 동작한다.

- InvokeRepeating을 통해 반복적으로 함수를 실행시킬 수 있다.
    -> CancelInvoke 혹은 오브젝트를 파괴하여 종료해주어야 한다.

- 지연 시간 뒤에 함수를 실행시킬 수 있다. (단순히 일정 시간 뒤에 함수를 실행시킬 뿐이다)

Invoke("함수명", "지연시간");

 

- Reflection을 통해 값을 가져온다. (코루틴 보다 느리다) 

더보기

Reflection

프로그램 실행 중 어셈블리의 내용을 확인하거나, 검사하려는 경우 사용되는 기능

 


코루틴과 멀티쓰레딩의 차이

 

 

코루틴

- 코루틴은 동기 동작이다

더보기

동기 => 요청을 보낸 뒤 그 요청의 결과값을 얻기까지 작업을 멈추는 것

비동기 => 요청을 보낸 뒤 그 요청의 결과값이 오지 않아도 다른 작업을 수행하는 것

- 단일 스레드에서 실행된다 (유니티는 단일 스레드)

- 코루틴은 yield return를 통해 현재 위치를 기억을 하고 수행 권한을 넘긴다. 이 과정이 마치

여러 개의 쓰레드가 동시에 동작하는 것과 같게 보이는 것.

 

 

멀티 쓰레드

- 한 프로세스 내에 실행되는 여러 개의 작업의 단위

 

- 프로세스는 독립된 힙 메모리 영역을 할당받고, 그 프로세스 내의 쓰레드는 독립된 스택 메모리 영역을 할당받는다. 

- 여러 작업을 수행해야할 때 스케쥴링이 이루어진다

   (스케쥴링 : 어떤 쓰레드 작업을 먼저 수행할지, 어떤 쓰레드를 더 많이 수행해야 효율적인지)

 

 

 

예시

1. InvokeRepeating을 통해 반복 실행 중인 메서드는 오브젝트를 비활성화하면 멈출까요?

-> 멈추지 않는다. 


2. Coroutine을 통해 반복 실행 중인 메서드는 오브젝트를 비활성화하면 멈출까요?

-> 멈춘다. (비활성화 후 다시 오브젝트를 활성화 시키더라도 코루틴은 실행되지 않는다)


3. 다음 Coroutine 코드의 성능 상 문제는 무엇이 있을까요? (Hint : 메모리)

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

 

- 위의 코드에서 new를 통해 새로운 인스턴스를 생성하고 있다. 

이 과정에서 Garbage가 생성된다.

캐싱하여 해당 코드의 성능을 높일 수 있다.

- 고정된 시간이 아닌 경우? -> 따로 타이머를 만들어 타이머 마다 실행되도록 한다

private IEnumerator Fade(flaot delayTime)
{
    Color c = renderer.material.color;
    float curTime = 0f;
    bool isReady = false;

    for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
    {
        if (!isReady)
        {
            curTime += Time.deltaTime;
            if (curTime >= delayTime)
                isReady = true;
        }
        else
        {
            c.a = alpha;
            renderer.material.color = c;
            isReady = false;
            curTime = 0f;
        }

        yield return null;
    }
}


    


4. Unity의 Coroutine은 비동기 동작일까요? 비동기 동작이라면 하나의 스레드에서 동작하지 않는걸까요?

-> 동기 동작이다. 다만 수행 속도가 너무 빨라 비동기 동작 처럼 보이는 것이다.

유니티는 한 번에 한 동작만 수행하는 단일 스레드 방식을 사용한다.

즉 코루틴은 하나의 단일 스레드에서 비동기 처럼 작동하는 동작이다.

'Study > 개념 정리' 카테고리의 다른 글

[Study] Tree  (0) 2024.07.18
[Study] 최적화  (0) 2024.07.17
[Study] MonoBehaviour와 Unity 생명주기  (0) 2024.07.15
[Study] Queue  (0) 2024.07.12
[Study] Stack  (0) 2024.07.11