Today I Learned - Day 7 [쓰레드 분기]
금일은 C#에서의 쓰레드 분기법에 대해서 정리해 보았다.
단, Unity에서는 메인 쓰레드 이외의 쓰레드에서 MonoBehavior 클래스를 처리할 경우 Can only be called from the main thread 에러가 발생하므로 주의해야 한다.
대신, Unity에서 대처방안으로 '데이터 지향 프로그래밍(소위 DOTS라고 불림)'이라는 새로운 개념을 소개하고 있다.
해당 사항도 포함해서 쓰레드 분기에 대해서 다뤄보자.
쓰레드를 분기시키는 이유
어지간한 CPU들은 모두 멀티코어, 멀티쓰레드로 나오는 현 시대에서 하나의 쓰레드로 주구장창 진행하는 것은 효율이 매우 낮다. 공부할 때 작업하는 단순한 프로젝트들이면 몰라도, 수많은 연산이 필요한 프로젝트를 진행할 때 하나의 쓰레드만 운용한다면 그 속도는 (안좋은 의미로) 볼 만 할 것이다.
이러한 문제를 해결하기 위한 것이 바로 멀티 쓰레딩으로, 하나의 프로그램이 여러 쓰레드를 운용하도록 하여 그 속도를 크게 높일 수 있는 프로그래밍 기법이다.
이러한 이유로, 프로그래밍을 공부한다면 빼놓을 수 없는 고급 테크닉 중 하나가 멀티쓰레딩인 것이다.
C#의 쓰레드 분기 방법 - Thread 클래스
System.Threading 패키지에 포함된 클래스로, 멀티 쓰레딩을 구성할 수 있도록 만들어 주는 클래스다.
사용법은 다음과 같다.
Thread thread = new Thread(Function);
thread.Start(object Argument);
void Function(object Argument)
{
Unpacking Argument
Function Content
}
이렇게 구성하면 Function 함수를 구동하는 쓰레드가 생성되어 thread 변수에 할당된다.
만약 구동하려는 함수가 인수를 필요로 한다면 Start()에 패킹하여 전달한 뒤, 함수에서 언패킹 해서 사용해야 한다.
이외에도 복수의 인수가 필요하다면 클래스나 구조체를 사용하여 한 번에 넘겨줘야 한다.
이러한 방법도 있다.
Thread thread = new Thread(() => Function(object Argument));
thread.Start();
void Function()
{
Unpacking Argument
Function Content
}
이렇게 작성할 경우, 인수도 함수와 함께 넘겨줄 수 있어 전체적으로 보기가 편해진다.
대신 구동할 때 넘겨주는 방식이 아니기 때문에 상황에 따라서 다른 인수를 사용하는 경우에는 다소 난감해질 수 있다.
[물론, 그냥 쓰레드 할당 자체를 늦게 하면 되기에 큰 문제는 아니다.]
Thread와 관계된 함수 [thread는 Thread 오브젝트, Thread는 Thread 클래스를 의미한다.]
- thread.Join(): thread 쓰레드가 종료될 때 까지 대기하는 함수.
- Thread.Sleep(a): 현재 쓰레드를 a밀리초 동안 대기시킨다.
- thread.Abort(): thread 쓰레드를 강제로 종료시키는 함수.
Unity에서의 멀티쓰레딩
상술했듯이, Unity에서는 Thread를 활용하기가 다소 많이 난감하다. MonoBehavior만 아니라면 서브 쓰레드에서 처리할 수 있긴 하지만, 게임 오브젝트에 관여할 수 있는 것이 MonoBehavior인 만큼 활용하기가 쉽지는 않은 편.
그에 대처하기 위해서 Unity에서 제시한 대안이 2가지 존재한다.
1. 코루틴
엄밀히 말하면 멀티쓰레딩은 아니고, 하나의 쓰레드로 복수 연산을 수행할 수 있는 방법에 해당한다.
MonoBehavior에서만 쓸 수 있는 방법으로, 각 코루틴이 Update 함수 직후에 순차적으로 연산을 수행하는 기법.
메인 쓰레드 하나가 모두 다 수행하는 구성이긴 하나, 코루틴 자체가 가벼운 편이라서 속도는 빠르다.
2. 데이터 지향 프로그래밍
멀티 쓰레딩을 활용하기 위해서 Unity측에서 주창한 개념.
간단하게 정리하자면, 데이터 연산은 서브 쓰레드에서 진행한 다음, 처리 완료된 데이터를 데이터를 담아두는 객체를 통해 메인 쓰레드에게 전달하여 게임에 적용하는 방식을 말한다. DOTS(Data-Oriented Technology Stack)은 이를 위한 기술을 말하는 용어.
다만, 기능 하나를 복수 함수로 쪼개서 구현하는 데다가 쓰레드 간 통신 까지 구현하면서 작업해야 하는 지라, 일반적인 개발 방식에 비해서 코드 정리나 버그 검출 들이 심히 복잡하다는 것이 문제. 어지간하면 기존 코딩 방식을 사용하는 것이 좋다.