본문 바로가기
Study

Unity, 코루틴과 멀티쓰레드의 차이

by Client. DJ 2022. 2. 12.
반응형

코루틴과 멀티쓰레드

코루틴을 통하여 마치 멀티 쓰레딩을 할 수 있지만, 사실 이는 멀티 쓰레딩과는 거리가 있습니다.

코루틴(Coroutine)

매 프레임마다 스케쥴링으로 관리가 됩니다. 매 프레임에서 IEnumerator의 반복기 형태로 호출되며 체크합니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CoroutineTest : MonoBehaviour
{
	private void Start()
	{
		StartCoroutine(DelayedHelloWorld(2f));      // 2초 뒤에 출력
		StartCoroutine(DelayedHelloWorld(1f));      // 1초 뒤에 출력
		StartCoroutine(DelayedHelloWorld(3f));      // 3초 뒤에 출력
	}

	private IEnumerator DelayedHelloWorld(float seconds)
	{
		yield return new WaitForSeconds(seconds);
		Debug.Log("Hello World!");
	}
}

위와 같이 코루틴을 사용하면 각각 따로 함수가 호출된 것처럼 사용할 수 있습니다. 이는 마치, 쓰레드와 사용했을 때와 같거나 또는 유사한 결과가 나옵니다. 유사한다는 이유는 아래에서 알 수 있습니다.

매 초마다 출력한다.

쓰레드(Thread)

쓰레드는 하나의 프로세스 단위를 말합니다. 하나의 프로그램에서 하나의 프로세스만 쓰는 것이 아닌 여러 개를 사용할 수 있습니다. 반면에 유니티는 단일 쓰레드로만 작동하는 엔진이어서 유니티로만 C#을 공부했다면 모르거나 헷갈려하는 사람들이 꽤있습니다.

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

public class TheadTest : MonoBehaviour
{
	private void Start()
	{
		Thread thread1 = new Thread(() => DelayedHelloWorld(2f));
		Thread thread2 = new Thread(() => DelayedHelloWorld(1f));
		Thread thread3 = new Thread(() => DelayedHelloWorld(3f));

		thread1.Start();
		thread2.Start();
		thread3.Start();
	}

	private void DelayedHelloWorld(float seconds)
	{
		Thread.Sleep((int)(1000 * seconds));
		Debug.Log("Hello World!");
	}
}

코루틴과 똑같은 결과가 나온다.

차이점

결과를 두고 봤을 때는 같은 결과를 출력하고 있지만, 코루틴은 하나의 쓰레드에서 스케쥴링으로 관리가 되고 있습니다. 반면 멀티 쓰레드로 구성을 했을 경우, 예외 상황이 많이 생기며 (주로 데드락), 각 프로세스마다 우선권을 주기 위해서 관리되는 기법들도 있습니다. (Join() 호출, 뮤텍스, 셰마포어)

이해

  • 코루틴은 아래와 같이 단일 쓰레드로 매 프레임마다 코루틴을 체크합니다. 시간으로 조건을 주었으니 매 프레임마다 흐른 시간을 체크한다고 생각하시면 되겠습니다.
  • 이는 지연실행의 개념으로 '1' frame 체크를 한 뒤에 호출이 되겠습니다. (1프레임이 지남, 조건이 충족되었는지 확인)
  • 디버깅을 통해 이를 확인할 수 있습니다. (디테일하게 체크를 하면 원하는 타이밍보다 한 템포 늦게 확인이 됩니다.)

코루틴(1개의 쓰레드)

 

  • 반면 쓰레드는 아래와 같이 각각 프로세스가 따로 돌아가면서 일 처리를 합니다.

멀티 쓰레드(3개의 쓰레드)

 
쓰레드는 어떤 프로세스가 먼저 실행되고 종료될지는 알 수가 없습니다.(순서 보장되지 않음) CPU성능에 맞춰 적당히 분배해서 실행해준다고 생각하시면 됩니다.
 

마무리

예전에 이해는 했지만 설명을 제대로하지 못 해서, 따끔하게 혼났던 기억이 있네요. 머리로는 이해했지만 설명을 제대로 하지 못 한다면 그 역시 모르는 것과 같다고 하셨던 한마디가 아직도 기억에 남습니다.

 

유니티는 그렇다고 싱글 쓰레드만 사용하는 것일까요?

아닙니다. 랜더링, 여러 업데이트들 호출하기 위한 부모 로직, 코루틴, 인보크 등 여러가지가 돌아가기 위해서 백그라운드 워커 쓰레드가 실행 중이며, 프로파일러를 통해 확인이 가능합니다. 단일 쓰레드만 사용한다는 전설은 어디서 나온걸까요?

반응형

댓글