이전 글에서는 벌스(Verse)의 Failure 개념이 왜 중요한지를 정리해보았습니다.
특히 벌스는 실패 가능성을 단순 런타임 오류 수준으로 처리하기보다,
언어 안에서 비교적 직접적으로 표현하려는 특징을 가지고 있다는 점도 함께 살펴보았습니다.
이번 글에서는 벌스의 또 다른 핵심 요소 중 하나인 동시성(Concurrency)에 대해 정리해보려고 합니다.
현대 게임은 동시에 수많은 작업이 발생한다
최근 게임들은 단순 싱글플레이 구조보다 훨씬 복잡한 환경 위에서 동작합니다.
특히 멀티플레이 게임에서는 수많은 플레이어와 이벤트,
상태 변화가 동시에 발생하게 됩니다.
예를 들어 여러 플레이어가 같은 객체를 동시에 접근할 수도 있고,
서로 다른 이벤트가 거의 같은 시점에 실행될 수도 있습니다.
또한 실시간 온라인 게임에서는 네트워크 이벤트와 애니메이션 재생,
AI 업데이트와 UI 반응,
물리 처리와 상태 동기화 같은 작업들이 계속 동시에 발생합니다.
게임 규모가 커질수록 이런 상황은 더욱 복잡해집니다.
특히 최근 라이브 서비스 기반 게임들은 게임 실행 중에도 상태가 계속 변화합니다.
플레이어가 접속하고 떠나며,
새로운 이벤트가 생성되고,
서버 상태 역시 계속 변경됩니다.
즉, 최근의 게임은 단순히 “코드를 순서대로 실행하는 구조”만으로 설명하기 어려운 환경으로 계속 발전하고 있습니다.
동시성은 단순히 멀티스레드 문제만은 아니다
동시성이라는 단어를 보면 멀티스레드부터 떠올리는 경우가 많습니다.
물론 동시성과 멀티스레드는 서로 관련이 있습니다.
하지만 동시성은 단순히 “스레드를 여러 개 사용한다”는 의미만 이야기하는 개념은 아닙니다.
조금 더 정확히 말하면 여러 작업이 서로 독립적으로 진행되거나,
동시에 실행 가능한 상태를 얼마나 안정적으로 관리할 수 있는가에 더 가까운 문제입니다.
예를 들어 플레이어가 아이템을 사용하는 동안 애니메이션이 재생되고,
동시에 UI가 갱신되며,
네트워크 이벤트까지 처리되는 상황을 생각해볼 수 있습니다.
또한 온라인 게임에서는 서버와 클라이언트 사이의 상태 변화도 계속 발생합니다.
어떤 플레이어는 이동하고,
다른 플레이어는 공격을 수행하며,
또 다른 시스템에서는 AI가 행동을 결정할 수도 있습니다.
그리고 이런 작업들은 서로 영향을 주면서 동시에 진행됩니다.
즉, 동시성 문제는 단순히 “성능을 향상시키는 기술” 보다,
복잡한 상태 변화를 얼마나 안정적으로 관리할 것인가와 훨씬 더 깊게 관련되어 있습니다.
기존 게임 엔진도 이미 동시성 문제를 해결해오고 있었다
사실 기존 게임 엔진들도 오래전부터 동시성 문제를 해결하기 위해 다양한 구조를 사용해왔습니다.
유니티의 코루틴(Coroutine)이 대표적인 예시 중 하나입니다.
IEnumerator FadeRoutine()
{
yield return new WaitForSeconds(1.0f);
}
코루틴은 함수 본문 전체가 실행되지 않더라도 yield 구문을 사용해 실행 중간에 멈췄다가 나중에 다시 실행할 수 있습니다.
언리얼 엔진 역시 Latent Action이나 Async Task 등을 사용합니다.
즉, 최근의 게임 엔진은 이미 오래전부터 “순차 실행만으로는 부족하다”는 문제를 계속 해결해오고 있었습니다.
그리고 벌스는 이런 문제를 단순 라이브러리 수준보다,
언어 차원에서 더 직접적으로 다루려는 특징을 가지고 있습니다.
suspends 문법이 중요한 이유
벌스 함수를 보면 suspends 키워드가 붙는 경우를 볼 수 있습니다.
OnBegin<suspends>() : void =
이 구조는 현재 함수가 실행 도중 일시 중단될 수 있다는 의미를 표현합니다.
즉, 함수가 반드시 처음부터 끝까지 한 번에 실행되어야 한다는 것을 의미하지 않습니다.
예를 들어 특정 이벤트를 기다리거나,
일정 시간 대기하거나,
다른 작업이 끝나기를 기다리는 상황이 발생할 수 있습니다.
그리고 이런 구조는 실시간 온라인 환경에서 굉장히 중요할 수 있습니다.
멀티플레이 게임에서는 수많은 이벤트가 동시에 발생하기 때문에,
특정 작업 하나가 전체 시스템을 멈추게 만들면 안 되기 때문입니다.
벌스는 이런 문제를 언어 안에서 비교적 자연스럽게 표현하려고 하고 있습니다.
특히 이 부분은 기존 게임 스크립트 언어와 비교했을 때 꽤 큰 차이를 만들어냅니다.
Coroutine이나 Async 기능을 “추가 기능”처럼 제공하는 수준보다,
동시성 자체를 언어의 핵심 기능 안에서 제공하고 있기 때문입니다.
Failure와 동시성은 서로 깊게 관련되어 있다
이전 글에서 이야기했던 Failure 개념 역시 동시성 문제와 깊은 관련이 있습니다.
멀티플레이 환경에서는 특정 연산이 항상 성공한다고 가정하기 어려워집니다.
예를 들어 어떤 플레이어가 이미 제거된 객체를 접근하려 하거나,
다른 시스템이 먼저 상태를 변경해버리는 상황도 충분히 발생할 수 있습니다.
또한 여러 작업이 동시에 같은 상태를 변경하려고 시도할 수도 있습니다.
즉, 실시간 온라인 환경에서는 “실패 가능한 상황” 자체가 훨씬 자주 발생합니다.
그리고 이런 환경에서는 실패 가능성을 코드 안에서 직접 표현하고,
안전하게 처리할 수 있어야 합니다.
벌스는 Failure와 동시성 문제를 서로 분리된 기능처럼 다루기보다,
하나의 플랫폼 안에서 함께 해결하려는 특징이 강하게 보입니다.
Epic은 왜 동시성을 언어 차원에서 다루려고 할까?
Epic이 최근 중요하게 바라보는 방향을 보면 이유를 어느 정도는 이해할 수 있을 것 같습니다.
특히 포트나이트와 UEFN을 보면 단순한 게임 제작 툴이라기 보다,
대규모 온라인 플랫폼에 가까운 형태로 계속 발전하고 있습니다.
그리고 이런 환경에서는 수많은 플레이어와 실시간 이벤트,
사용자 제작 콘텐츠와 지속적으로 변경되는 상태들을 동시에 처리해야 합니다.
즉, 로컬에서 실행되는 독립형 게임보다 훨씬 복잡한 실행 환경을 기본 전제로 둡니다.
이런 구조에서는 동시성과 상태 관리를 얼마나 안정적으로 처리할 수 있는지가 굉장히 중요할 수 있습니다.
특히 UEFN처럼 수많은 사용자가 동시에 다양한 게임 로직을 작성하는 환경에서는,
플랫폼 전체의 안정성을 유지하는 문제도 매우 중요합니다.
그리고 벌스는 이런 환경을 강하게 의식하고 설계된 언어처럼 보입니다.
즉, 단순한 “게임 스크립트 언어”를 넘어서,
실시간 온라인 플랫폼을 위한 언어에 가깝게 설계하는 것을 목표로 하고 있는 것입니다.
동시성 문제는 앞으로 더 중요해질 가능성이 높다
최근 게임 산업은 실시간 온라인 환경과 사용자 제작 콘텐츠,
라이브 서비스 구조 중심으로 계속 발전하고 있습니다.
그리고 이런 환경에서는 동시에 처리해야 하는 작업 수 역시 계속 증가하게 됩니다.
특히 AI 시스템과 네트워크 이벤트,
실시간 상호작용 구조가 복잡해질수록 동시성 문제는 더욱 중요해집니다.
또한 앞으로는 단순한 게임 수준을 넘어,
수많은 사용자가 동시에 접속하는 온라인 월드 형태가 더욱 증가할 가능성이 높습니다.
그리고 이런 환경에서는 상태 변화와 이벤트 처리,
패 가능성을 얼마나 안정적으로 관리할 수 있는지가 플랫폼 전체 품질에 직접적인 영향을 미칩니다.
벌스는 이런 시대의 변화를 강하게 반영하고 있는 언어인 것처럼 생각됩니다.
마무리
벌스의 동시성 구조는 단순히 비동기 기능 수준에서 끝나는 개념이 아닙니다.
실시간 온라인 환경 안에서 수많은 상태 변화와 이벤트를 안정적으로 관리하기 위한 핵심 구조에 가깝습니다.
특히 suspends 같은 문법 요소들은 이런 특징을 비교적 직접적으로 보여주는 구조 중 하나입니다.
또한 Failure와 option 타입 같은 요소들 역시 동시성 문제와 함께 동작하면서,
플랫폼 전체의 안정성을 높이기 위해 발전하고 있는 것 같습니다.
그리고 이런 특징들은 Epic이 앞으로 구축하려는 대규모 온라인 플랫폼과도 깊게 관련되어 있습니다.