.NET 환경의 C# 서버를 구현하는 것은 아니지만,
비록 백엔드 부분이 nodejs와 socket.io를 이용하지만,
연동되는 클라이언트 파트는 C# 기반의 Unity 엔진이기 때문에, 멀티 쓰레드에 대한 고려가 필요하다.
노드 환경은 기본적으로 싱글 스레드 기반으로 event loop와 비동기 I/O 모델을 사용한다.
따라서 async/await 구문을 중점적으로 간편하게 단일 스레드만 고려하여 개발을 진행하면 된다.
물론, 싱글 스레드란 구조적인 부분에서 기인하는 문제로 CPU를 많이 사용하는 계산량에 대한 성능 저하 가능성이 존재한다.
이와 달리 C# 은 멀티 스레드를 지원하는 환경으로, Thread
와 Task
를 이용하여 멀티 스레드를 사용 가능하여 병렬 작업을 진행할 수 있다.
대부분의 유니티 API는
main thread
에서만 접근 가능하다.
즉, 유니티에서는 메인 쓰레드를 통해 단일 메인 로직을 구현하고,
Coroutine
을 통해 Thread의 개념을 수행한다.즉, Coroutine을 통해 Unity API를 사용하며 비동기 병렬 처리할 수 있으나,
직접Thread
를 사용할 경우 Unity API는 사용이 불가하다.
// 전처리 쓰레드 네임스페이스
using System.Threading;
using System.Threading;
private bool IsMainThread()
{
return Thread.CurrentThread.ManagedThreadId == 1;
}
이런 쓰레드를 이용하여 CPU Bound Task들에 대해 병렬 처리를 통한 성능 향상의 장점을 얻을 수 있다.
다만, 역시나 Synchronization과 관련한 문제들이 주요 단점이다.
이와 관련해서 알아두면 좋은 내용이 바로 EAP와 TAP이다.
주로 이벤트, 델리게이트 모델을 사용하여 보류 중인 async 작업과 통신하는 모델이다.
EAP는 시스템의 흐름을 event란 독립적 동작으로 제어하는 패러다임으로, 보통의 게임에서는
상태변화
, 유저 입력
, 네트워크 요청
과 같은 이벤트가 주요하다.
구현에 있어서 주로 *METHOD_NAME*Async
메서드, *METHOD_NAME*Completed
이벤트를 통해 Event Listener와 callback 함수로 이루어진다.
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (sender, e) => {
// 비동기 작업 실행
};
worker.RunWorkerCompleted += (sender, e) => {
// 비동기 작업 완료 후 결과 처리
};
worker.RunWorkerAsync();
이벤트 발생 시마다 처리하는 방식으로 직관적인 구현이 가능하나,
콜백 함수들의 남용으로 콜백지옥과 같은 단점이 존재한다.
TAP의 비동기 메서드는 Task
, Task<TResult>
, ValueTask
및 ValueTask<TResult>
와 같은 대기할 수 있는 형식을 반환하는 메서드의 작업 이름 뒤에 Async 접미사를 포함한다.
즉, 간단히 말해 Task
객체로 감싼 비동기 작업에 대해, async
와 await
키워드로 직관적으로 병령 처리를 한다.
C# 에서는 현대적인 비동기 프로그래밍 패러다임으로 TAP를 널리 사용하는 추세이다.