유니티 코루틴 사용 시 문제점 & 주의할 점

PTK·2025년 2월 21일
0

코루틴(Coroutine)을 사용할 때 주의해야 할 점과 발생할 수 있는 문제점들을 정리해 보았다.

1. 코루틴이 자동으로 멈추지 않음

StartCoroutine()으로 시작한 코루틴은 StopCoroutine() 또는 StopAllCoroutines()을 호출하지 않는 한 계속 실행된다. 특히 게임 오브젝트가 비활성화되거나 삭제되더라도, 해당 코루틴은 계속 실행될 수 있다.

해결 방법: StopCoroutine()을 사용하여 명시적으로 종료.

IEnumerator ExampleCoroutine()
{
    while (true)
    {
        Debug.Log("Running...");
        yield return new WaitForSeconds(1f);
    }
}

private void OnDisable()
{
    StopCoroutine(ExampleCoroutine()); 
}

2. 코루틴이 여러 번 실행될 수 있음 (중복 실행 문제)

StartCoroutine()을 여러 번 호출하면 같은 코루틴이 여러 개 실행될 수 있다. 이는 메모리 낭비와 예기치 않은 동작을 유발할 수 있다.

해결 방법: bool 플래그 사용하여 중복 실행 방지. 기존 코루틴이 실행 중이면 새로 시작하지 않도록 체크.

private Coroutine runningCoroutine;

public void StartMyCoroutine()
{
    if (runningCoroutine == null)  
        runningCoroutine = StartCoroutine(MyCoroutine());
}

private IEnumerator MyCoroutine()
{
    yield return new WaitForSeconds(5f);
    runningCoroutine = null; // 실행이 끝나면 초기화
}

3. 코루틴에서 yield return null이 성능 저하를 유발할 수 있음

yield return null을 사용하면 매 프레임마다 실행됨, 따라서 불필요한 호출이 많아지면 성능 저하 발생 가능 하다.

해결 방법: WaitForSeconds() 또는 WaitForEndOfFrame()을 사용하여 실행 빈도를 조절.

IEnumerator BadCoroutine()
{
    while (true)
    {
        // 불필요하게 매 프레임 실행
        Debug.Log("Running...");
        yield return null;
    }
}

// 더 나은 방법: 특정 간격으로 실행
IEnumerator OptimizedCoroutine()
{
    while (true)
    {
        Debug.Log("Running...");
        yield return new WaitForSeconds(1f); // 1초마다 실행
    }
}

4. 코루틴 내에서 무한 루프 조심

while (true) 루프를 사용할 경우 무한 루프가 발생할 가능성이 있다.

해결방법: 루프 내에서 yield return을 항상 포함해야 한다. 특정 조건에서 break;를 사용하여 안전하게 종료.

IEnumerator SafeLoop()
{
    int count = 0;
    while (count < 10) // 특정 조건으로 제한
    {
        Debug.Log("Running: " + count);
        count++;
        yield return new WaitForSeconds(1f);
    }
}

5. 게임 오브젝트가 삭제되면 this가 null이 됨

코루틴이 실행되는 도중에 게임 오브젝트가 삭제되면 this가 null이 되고, Unity가 예외를 발생시킬 수 있다.

해결 방법: this == null 또는 gameObject == null 체크 후 종료.

IEnumerator CheckBeforeUse()
{
    while (true)
    {
        if (this == null) yield break; // 코루틴 안전 종료
        Debug.Log("Still Running...");
        yield return new WaitForSeconds(1f);
    }
}

6. 코루틴 내에서 Try-Catch 예외 처리 필요

코루틴 내부에서 예외가 발생하면 Unity는 오류를 출력하지만 코루틴 자체는 종료된다.

해결 방법: try-catch 문을 사용하여 예외 처리.

IEnumerator SafeCoroutine()
{
    try
    {
        yield return new WaitForSeconds(1f);
        int result = 10 / int.Parse("0"); // 예외 발생 가능
    }
    catch (System.Exception e)
    {
        Debug.LogError("코루틴에서 예외 발생: " + e.Message);
    }
}

코루틴 사용 시 최적화 체크리스트

  1. 불필요한 yield return null을 피하고, WaitForSeconds() 사용
  2. StartCoroutine() 중복 실행 방지 (bool 변수 사용)
  3. StopCoroutine() 또는 OnDisable()에서 정리
  4. while (true) 사용 시 yield return 필수 포함
  5. 예외 발생 가능성이 있는 경우 try-catch 사용
  6. 멀티스레딩이 필요한 경우 async/await 고려

추가)

Invoke

Invoke는 특정 시간 후에 메서드를 한 번 호출하는 기능을 제공하는 Unity의 내장 함수이다.

일정 시간이 지난 후, 지정한 메서드를 한 번만 실행함.
InvokeRepeating()을 사용하면 일정 간격으로 반복 실행할 수도 있음.

using UnityEngine;

public class Example : MonoBehaviour
{
    void Start()
    {
        // 3초 후에 "PrintMessage" 메서드 실행
        Invoke("PrintMessage", 3f);
    }

    void PrintMessage()
    {
        Debug.Log("3초 후에 실행되었습니다!");
    }
}

코루틴과 인보크의 차이점

결론

Invoke는 특정 시간 후에 메서드를 실행하는 간단한 기능
InvokeRepeating()을 사용하면 일정 간격으로 반복 실행 가능
CancelInvoke()로 예약된 실행을 취소할 수 있음
하지만 매개변수 전달이 불가능하고 제어가 어려우므로, 복잡한 타이밍 로직에는 Coroutine을 사용하는 것이 더 유리

0개의 댓글