Skip to content
This repository was archived by the owner on Jun 14, 2022. It is now read-only.

Latest commit

 

History

History
39 lines (33 loc) · 2.59 KB

background_thread.md

File metadata and controls

39 lines (33 loc) · 2.59 KB

백그라운드 스레드를 파이버와 어울려 사용하기

배경

실버바인 서버 엔진 2는 내부적으로 스레드 여러 개를 만들어서 DB 접근 등의 일을 처리하지만,
게임 로직 코드는 오직 메인 스레드에서만 돌립니다.
대신 파이버를 사용해서 여러 로직 코드가 동시에 (concurrently) 실행될 수 있도록 하고 있습니다.
이는 스레드 동기화 부담을 로직 프로그래머에게 지우지 않으면서도, I/O 대기로 인한 성능 저하가 일어나지 않도록 하는 설계입니다.

이런 설계에서는 게임 로직 코드가 동작하는 메인 스레드에서 blocking I/O를 실행하면,
I/O 결과가 돌아올 때까지 메인 스레드 전체가 멈추기 때문에, 심각한 성능 저하가 발생합니다.
그런데 .NET 내장 라이브러리는 물론이고, 수많은 서드파티 라이브러리들이 blocking I/O 모델을 채택하고 있기 때문에, 엔진이 제공하는 API 이외의 방법으로 I/O(주로 외부 시스템과의 통신이겠죠)를 할 때는 매우 주의해야 합니다.

백그라운드 스레드에서 작업을 수행한 후 메인 스레드에서 계속하기

실버바인 서버 엔진 2에서는 blocking I/O를 메인 스레드가 아니라 백그라운드 스레드에서 수행하고,
I/O가 끝났을 때 파이버를 통해 결과를 받을 수 있는 인터페이스를 제공하고 있습니다.

Func<T> work;
var result = await EngineAPI.ThreadPool.Execute<T>(work);

이렇게 하면 됩니다.
work는 .NET 프레임워크에서 제공하는 ThreadPool.ExecuteInThreadPool 을 통해 실행됩니다.
work가 정상적으로 수행을 마치면 그 결과가 await 식의 결과로 전달됩니다.
work 안에서 예외가 발생하면 그 예외가 Exception으로 한번 감싸져서 호출한 파이버로 전달됩니다.
work는 다른 스레드에서 실행되므로, 메인 스레드와 공유하는 상태를 변경하지 않도록 주의하셔야 합니다.

백그라운드 스레드에 작업을 발주하고 결과를 무시하기

EngineAPI.ThreadPool.FireAndForget(() => {})

이렇게 하면 됩니다.

백그라운드 스레드에서 메인 스레드로 작업을 밀어넣기

반대로, 파이버와는 상관없이, 백그라운드 스레드에서 발생한 사건을 메인 스레드로 넘겨서 처리하고 싶은 경우에는 이렇게 하면 됩니다.

EngineAPI.ThreadPool.QueueToMainThread(() => {})

인자로 넘긴 Action이 메인 스레드 안에서 실행되게 됩니다.

쉽죠?