지난번에 싱글프로세스 vs 멀티프로세스를 했었는데 이번에는 싱글 쓰레드 vs 멀티 쓰레드 를 다뤄보겠습니다.
싱글 쓰레드는 하나의 프로세스에 Work Thread가 하나인 경우를 말하고, 멀티 쓰레드는 하나의 프로세스에 Work Thread가 여러개인 경우를 말합니다.
싱글 프로세스이면서 멀티 쓰레드를 쓸 수 있고, 멀티 프로세스이면서 싱글 쓰레드를 쓸 수 있고, 멀티 프로세스이면서 멀티 쓰레드를 쓸 수 있습니다.
싱글 프로세스이면서 싱글 쓰레드를 쓸 수 있지만 현재 시점에선 공짜점심이 끝난 상황에서 싱글 프로세스로 가려면 서버 머신이 좋아야 하는데 이미 서버 클럭수는 한계에 부딫혔기 떄문에 클럭 수가 더 늘어나기에는 기대하기 힘들고, 코어 수만 늘어나고 있고, 16개 코어까지도 가능한데 이 코어들의 성능을 다 뽑아먹기 위해서는 멀티 쓰레드가 필수적인 상황이 되었습니다.
그렇기 때문에 싱글 프로세스에 싱글 쓰레드는 말이 되지 않습니다.
그리고 프로세스와 상관없이 싱글 쓰레드와 멀티 쓰레드로 갈 수 있습니다.
그러면 멀티 쓰레드로 갔을 때의 관건은 쓰레드를 어떻게 나눌 것인가? 가 관건이 되는데요.
저번에 얘기 했듯이 성능이 코어 수가 증가되면서 성능이 1:1로 비례되서 증가되지 않습니다. 코어가 늘어나더라도 성능이 올라가는 폭은 점점 감소되는 형태이죠.
코어 수가 많아지면 쓰레드간에 간섭이 빈번해지고, 자원을 서로 차지할려고 싸우게 되기 때문에 오히려 코어 수가 늘어날 수록 성능이 더 떨어지는 상황이 발생할 수 도 있게 됩니다.
그렇기 때문에 이 쓰레드를 어떻게 나누어야 하는지, 어떻게 나누어야 코딩을 더 잘할 수 있는지가 관건이 됩니다.
저번에 싱글 쓰레드, 멀티 쓰레드를 다루었을 때 말했지만 싱글 쓰레드 멀티프로세스가 이런 상황에서 봤을 때 결코 나쁜 상황이 아니라는 것입니다.
그럼에도 불구하고 멀티쓰레드를 하겠다, 코어의 성능을 끝까지 끌어오고 싶다. 한다면 관건은 쓰레드간에 경쟁인데
공유자원은 메모리를 의미하는데 어떤 공유된 같은 메모리 영역을 여러 쓰레드가 경쟁하면서 사용 할 경우에 이 메모리를 보호해 주어야 합니다.
이걸 보호하는 방법은 락을 거는 방법이 가장 대표적인데 락을 건다는 얘기는 여러 쓰레드가 경쟁을 한다는 것이고, 하나의 쓰레드가 락을 점유 했을 때 나머지 쓰레드들은 기다려야 한다는 것입니다.
그러면 이 기다리는 시간만큼 성능이 떨어지게 됩니다. 그래서 코어 수가 올라 갈 수록 경쟁이 치열해지고, 그 만큼 기다리는 쓰레드 수가 늘어나게 되는데 이 상황에서 어떻게 잘 분배해야 쓰레드 간에 서로 다투지 않고 사이좋게 나눠 사용 할 수 있을까? 하는게 중요한 사항이 됩니다.
이 방법을 몇가지 알아보죠!
1. 무식하게 한다.
아무런 대비도 없이 아무런 기준도 없이 그냥 워크 스레드 간에 경쟁을 붙이는 것입니다.
이 때 쓰레드들이 공유자원을 막 접근하게 되고, 락을 막 걸게되는데 지옥이 펼쳐집니다.
이렇게 했을 때 문제점은 첫째로 성능이 떨어집니다.
락을 걸면 경쟁이 치열해진다는 소리고, 경쟁이 치열해진다는 소리는 다른 쓰레드가 웨이팅 타임이 길어진다는 소리고, 웨이팅 타임이 길어진다는 소리는 성능저하로 이어진다는 의미이죠.
그리고 두번째로 데드락 상황이 많이 발생합니다.
그래서 데드락은 잡기가 힘들 뿐더러 발생하기 전까지 이걸 판단하기가 힘든 문제가 있고, 데드락이 발생 시 프로그램이 멈춰버리는 현상이 일어나죠.
3. 락킹을 쓰다 보면 서로간 경쟁이 치열해져서 Race Condition이 발생한다.
누가 더 먼저 차지하느냐에 따라 틀려지는 것을 의미하는 것인데 A가 먼저 들어가고 B가 나중에 들어가는 상황과 B가 먼저 들어가고 A가 나중에 들어가는 상황이 서로 다르게 발생합니다.
그러다 보니까 타이밍 이슈가 생기게 되죠. 컨트롤 할 수 없는 여러가지 상황이 생긴다는 의미입니다.
그래서 이 방법은 안 좋은 방식입니다. 라고 생각하면 됩니다.
그렇기 때문에 반드시 어떤 공유자원에 여러 쓰레드가 접근 하는데 그 쓰레드들이 어떻게 자원을 분배할 것인가의 기준을 반드시 세워야 하는데요. 자원을 나누는 첫번째 방법은 Actor기준으로 나누는 방식이 있습니다.
이 방식은 Akka방식이라고 볼 수 있는데 스칼라라는 언어가 있는데 거기서 제공하는 프레임워크 이름이 Akka입니다.
이 방식은 Actor가 기준이 됩니다. 게임에서는 캐릭터, NPC, 등등이 기준이 되는데 이 Actor들이 각각의 쓰레드를 가지고 있습니다.
서로 Actor간에는 서로 컨텍을 하지 않습니다. 그런데 게임은 Actor간에 Interaction이 가장 빈번하는 발생하는 프로젝트가 문제가 됩니다. 예를 들어 A가 B를 때리고 B가 A를 때리는 상황을 보자 A가 B를 때리면 A는 B의 상황을 알고 싶어 할 것입니다.
얼마 만큼의 데미지가 들어갔는지, 남은 HP는 얼마인지, 등등 서로간에 Interaction이 일어날 수 밖에 없죠.
그런데 이 Akka 방식은 Actor가 하나의 쓰레드를 점유하고 있고, 자기일은 자기가 하는데 그럴 때 Actor간에 통신은 어떻게 하게 될까요? 메세지를 통해 전송합니다.
만약에 A가 B를 공격했을 때 공격 메세지를 보낸다 했을 때 각 Actor마다 메세지를 저장하는 메세지 큐(Queue)가 있는데 메세지를 보내면 그 큐에 메세지가 저장 됩니다.
그래서 B가 자기 쓰레드를 가지고 Update될 때 자기에게 온 메세지를 읽어서 처리합니다.
서로 메일을 주고 받는다 생각하면 됩니다. 그래서 이런 방식은 Golang에서 제공하는 Channel이 바로 메세지 큐라고 생각하면 됩니다.
A가 있고 B가 있을 때 서로 채널을 통해서 통신하는 것과 똑같다고 보면 됩니다.
그리고 Akka 방식은 서로 컨텍하지 않기 때문에 서로 간섭이 일어나지 않습니다.
예를 들어 Actor A Actor B Actor C가 있을 때 Actor A가 B에게 메세지를 줄 때 Actor B는 자신의 메세지 큐에 적게 될 것이고, B가 다음번 Update 때 그 일을 처리할텐데 서로 간에 통신은 Lock을 걸 필요 없이 메세지만 던져주는 형태가 되기 때문에 Lock이 필요 없는 것이고, 자원이 공유되지 않습니다.
Actor는 Actor만의 고유한 자원을 가지고 있기 때문에 자원이 공유 되지 않습니다. 그래서 Lock을 걸 필요 없이 메세지를 통해서 통신이 되죠. 이상적으로는 그렇게 돌아 갈 수 있습니다만.....
현실은 그렇지 않습니다. 반드시 어떤 Actor A가 Actor B의 상태를 조회할 필요가 있습니다.
만약에 Actor A가 Actor B의 HP상태를 조회하고 싶다고 가정해보죠.
예를 들면 LOL에 상대 체력에 비례해서(상대 체력이 많으면 많이주고, 적으면 데미지를 적게주는) 데미지를 주는 챔피언이 있는데
그런 것을 구현하기 위해서 데미지를 구하고 싶어서 그래서 코드를 아래와 같이 작성했다고 했을 때
damage = B.getHP() * 0.15
데미지는 상대방의 HP를 Get해서 이것에 15%다 라고 했을 때 getHP()를 사용하여 상대방의 상태를 조회한다 했을 때
이걸 동기식으로 조회하는 게 제일 편합니다. 그래서 그냥 function을 B에게 날려서 B한테 return 받는게 제일 편한데 문제가 생기죠.
HP라는 메모리 영역이 공유 됩니다. 그러니까 B의 HP영역을 A가 조회하니까 공유 됩니다.
공유되다 보니까 자원을 보호하기 위해 여기서 Lock을 거는 상황이 생길 수 밖에 없습니다.
Akka방식이 Actor기준으로 쓰레드를 나누었다고 했지만 Lock을 잡을 수 밖에 없는 상황이 생깁니다.
만약 Lock을 안 잡고 싶다고 할 때
damage = B.getHP()
를 할 수 없는 상황이 생기는 건데 이것을 못할 때 기존의 메세지 방식으로 어떻게 처리해야 해야 하냐면
A가 B에게 getHP라는 메세지를 던지면 된다. 그 때 B가 자신의 메세지 큐에 넣어서 다음번 Update시에 메세지를 읽어서 자신의 HP가 얼마인지 응답을 보내주고, A가 받아온 HP를 바탕으로 데미지를 구해서 B에게 Deal메세지로 Deal을 하는 방식이 됩니다.
이렇게 되면 Lcok을 걸 필요는 없어지지만 요 상황들이 동기식으로 동작하기 때문에 코딩복잡도가 올라가게 되고, 그 뿐만 아니라
A가 B에게 getHP라는 메세지를 던져서 B가 자신의 메세지 큐에 넣어서 다음번 Update시에 메세지를 읽어서 자신의 HP가 얼마인지 응답을 보내주는 시점에서 B의 체력이 50이였다고 가정할 때 그런데 C라는 Actor가 B를 공격해서 B의 HP가 20으로 줄었습니다.
지금 이 상황이 조회할 때는 50이였는데 바로 20으로 줄어든 상황일 때 B가 A에게 HP를 알려줄 땐 50을 알려 줄 것입니다. 50을 알려줘서 A가 데미지를 50에 대해서 계산하지만 실제로 B의 HP는 20이여서 실제보다 데미지가 더 들어가는 상황이 발생하게 되는 것이죠.
비동기가 되고, Lock을 걸지 않기 때문에 이런 상황처럼 복잡한 문제들, 타이밍 이슈들이 생기게 됩니다.
그러다보니 Lock을 걸면 편한데, Lock을 걸면 자원이 공유되고, 자원이 공유되면 성능이 떨어지고, 데드락이 발생하는 여러가지 문제들이 생기게 되고, 그렇다고 Lock을 쓰지 않자니 복잡도가 올라가고, 비동기식으로 처리해야 하는 등의 여러가지 문제들이 생기게 됩니다.
이 방식이 Akka방식입니다. 그렇다고 어느게 좋다 나쁘다 말할 수 없습니다. 모든지 Trade off가 있기 때문입니다.
메세지 방식으로 쓰겠다 하면 복잡도 올라가고, 비동기식을 감수해야 하는 것이고, Lock 쓴다면 성능 떨어지는 것, 데드락 발생하는 것, 등등을 조심해야 합니다.
두번째 방식은 System기준으로 나누는 방식 입니다.
Akka 방식과 비슷한데 멀티 쓰레드 상황에서 Lock을 걸지 않겠다 하면 쓰레드를 나누고, 각 쓰레드 간에 통신은 채널, 메세지 큐를 통해서 서로 메세지를 주고 받는 방식으로 처리하는 방식이 가장 대표적이고, 지금에서는 가장 유일한 방법이라고 볼 수 있습니다.
문제는 이 쓰레드 나누는 기준을 무엇으로 나눌거냐?의 차이만 있을 뿐입니다. Actor기준으로 나누겠다면 Akka방식이 되는 것입니다. System기준으로 나누는 방식은 ECS구조인데 Entity Component System의 약자입니다.
Entity는 기준으로 보면 되는데 어떤 캐릭터가 될 수 있고, 게임안에서 활동하는 Actor가 될 수 있는데 Entity가 여러 컴포넌트(Component)를 가지고 있습니다.
예를 들면 어떤 NPC(Entity)가 있는데 이 NPC는 Flying이라는 컴포넌트를 가지고 있습니다. 그래서 날아다닐 수 있고,
Attack이라는 컴포넌트를 가지고 있어서 공격도 가능하고, Talk 컴포넌트를 가지고 있어서 대화도 가능한 NPC가 되는 것입니다.
이런식으로 어떤 컴포넌트를 가지고 있냐에 따라 Entity의 성격이 결정되는 방식이 ECS 방식이라고 생각하면 됩니다.
Entity는 컴포넌트를 가질 수 있는 단위라고 생각하면 되고, 컴포넌트(Component)는 어떤 데이터라고 볼 수 있습니다.
그래서 아까 Flying 컴포넌트를 가지고 있다 했을 때 flying speed, 고도, 등등의 날아 다닐 때 필요한 데이터를 가지고 있는 컴포넌트라고 합니다.
각 컴포넌트는 기능별로 쪼개지는데 각 기능별로 필요한 데이터를 가지고 있는게 컴포넌트입니다.
중요한 것은 컴포넌트는 데이터를 가지고 있는 것이지 어떤 기능을 가지고 있는 것이 아닙니다. 그래서 Class가 아니라는 것입니다.
Class는 상태와 기능을 같이 가지고 있는 것인데 컴포넌트는 상태는 가지고 있지만 기능을 가질 수가 없습니다.
그래서 컴포넌트는 Class가 아니라 C언어의 Struct 구조라고 봐도 됩니다. 순수하게 데이터만 가지고 있는 것입니다.
그러면 기능은 누가 가지고 있을까요? Flying에 대한 데이터는 컴포넌트가 가지고 있는데 Flying에 대한 기능은 컴포넌트가 가지고 있지 않습니다.
이 기능은 Entity가 가지고 있지 않습니다. Entity는 그냥 컴포넌트의 모음입니다. 상태도, 기능도 없이 어떤 컴포넌트를 가지고 있는지 정의합니다.
기능은 System이 가지고 있습니다. System은 기능의 단위입니다.
그래서 Flying System은 단순하게 기능만 담당하고, 데이터는 담당하지 않습니다. 데이터는 오로지 컴포넌트에서 가져오는 것입니다. 정리하자면 Entity는 단순하게 컴포넌트들을 가지고 있는 것이고, 이 Entity가 어떤 컴포넌트를 가지고 있냐에 따라서 이 Entity의 성격이 결정 됩니다.
컴포넌트는 단순히 기능을 가지지 않고 데이터만 가지고 있습니다. 데이터만 가지고 있어서 동작을 가능하게 하진 않는데 그 동작을 가능하게 해주는 것은 System입니다.
System은 여러 System이 있을 수 있는데 System은 기능을 담당할 뿐 데이터를 가지고 있지 않습니다.
데이터는 각 Entity가 가지고 있는 컴포넌트에서 가지고 와서 데이터를 처리합니다.
이러한 방식을 ECS 구조 방식이라고 합니다. ECS 구조는 나온지 얼마 안된 구조입니다. 옛날에는 컴포넌트가 데이터와 기능을 가지고 있었습니다. ECS 구조가 좋은 점은 서로간에 역할을 단순히 분산했기 때문에 역할분담이 명확해서 Entity는 어떤 컴포넌트를 가지고 있는지 정의하고, 컴포넌트는 데이터만 담당하고, 시스템은 기능만 담당하도록 분리시켰습니다.
어떻게 보면 MVC모델의 게임버전이라고 봐도 됩니다.
MVC 모델에 대해 잠깐 설명하자면 M은 Model, V는 View, C는 Control의 약자입니다.
M은 데이터, V는 화면, C는 기능을 나타내는 서로의 기능을 분리를 시키는 구조인데, 이 구조의 게임버전이 ECS 구조라고 보면 됩니다. 시스템이 서로간의 분리를 시킬 수 있게 되어 시스템 기준으로 쓰레드를 나눌 수 있습니다.
그래서 ECS 구조에서 크게 몇 가지 장점이 있는데
1. 확장이 굉장히 쉬워집니다.
Entity정의가 굉장히 유연합니다. 기존의 게임을 만드는 방식에서는 NPC는 NPC, 몬스터는 몬스터, PC는 PC인 식인데
ECS 구조에서는 NPC, 몬스터, PC 모두 다 Entity입니다.
어떤 컴포넌트를 가지고 있냐에 따라 성격이 달라지기 때문에 굉장히 확장이 좋아지게 되죠.
2. 데이터 로컬리티(Locality)가 좋아집니다.
데이터들이 모여 있는다는 의미입니다. 예를 들어 Drawing 컴포넌트가 있다고 가정하여 화면에 그림을 그리는 데이터들을 가지고 있는 컴포넌트라고 해보죠.
어떤 캐릭터를 화면에 그린다 했을 때캐릭터의 이미지가 필요할 것이고, 3D게임일 때 매쉬(Mesh)도 필요할 것이고, 텍스쳐, 등등이 필요할 것이고, 2D 게임이면 이미지가 필요할 것입니다. 이런 데이터가 있어야 실제로 Render System가 Drawing 컴포넌트의 데이터를 가지고 Drawing을 할 것입니다.
예를 들어보면 화면에 캐릭터가 10개 있고, Render System에서 10개의 이미지를 화면에 그려야 되는데 실질적으로 어떻게 그리냐면 Render System이 하는 일은 Entity중에 해당 월드에 존재하는 Entity들 중에 Drawing 컴포넌트가 있는 Entity들을 Render System이 미리 알고 있어서 그 Entity들을 돌면서 Drawing 컴포넌트의 데이터를 가져와서 그 데이터를 화면에 뿌려주는 역할을 합니다.
그럼 코드로 어떻게 될지 의사코드로 보게 되면
Foreach DrawComponent {
Draw(DrawComponent.Image)
}
Foreach로 Drawing 컴포넌트를 가지고 있는 모든 Entity들을 돌면서 DrawComponent 이미지를 Drawing 할 것입니다.
그래서 이미지란 데이터를 그냥 읽어서 드로잉 합니다.
그랬을 때 보면 이 DrawComponent.Image라는 것이 하나의 메모리 영역에 Array 형태로 모일 수 있습니다.
이렇게 모여있는 것을 데이터 로컬리티(Locality) 라고 합니다.
이 부분이 중요한데 캐시라는 것이 L1 ~ L4까지 위 그림처럼 있는데 L1캐시가 CPU코어에 붙어있고 그 옆으로 L2 ~ L4가 있고, L4 캐쉬는 서로 공유하고 있습니다.
속도로 보면 L1캐쉬가 제일 빠릅니다. 그 다음이 L2, L3이고, L4가 제일 느립니다.
그 옆에 메모리가 붙어있는데요. 그랬을 때 캐쉬로 올릴 때 한번에 꺼내올 때 근방의 데이터들을 한꺼번에 꺼내는데 데이터가 모여있으면 같은 캐시 라인에 같이 들어갈 확률이 높아집니다.
그러니까
요 것들이 L4 캐시 한 번 올릴 때 같이 올라가는 확률이 높아지는 것입니다. 같은 캐시라인에 올라가기 때문에 메모리로 다시 갈 필요가 없죠. A에 데이터 접근 한 다음에 B데이터에 바로 접근 하기 때문에 성능이 굉장히 빨라집니다. 그래서 데이터 로컬리티가 좋아지면 데이터를 순차적으로 읽을 때 성능이 굉장히 빨라집니다.
그런데 A와 B, C가 중구난방으로 있을 때, 그러니까 데이터 로컬리티가 지켜지지 않는 상황에서는 A를 그리기 위해 A를 먼저 캐시 라인에 들어가게 되고, 그 근방의 데이터를 한꺼번에 L4에 올리게 됩니다. 그 후 B를 그려야 하는데 이미 올라가있는 캐시에 B가 없기 때문에 L4캐시를 비우고 나서 B근방에 있는 메모리를 다시 올리게 됩니다. 그 후 C를 그릴 때 이미 올라가있는 캐시에 C가 없기 때문에 L4캐시를 비우고 C근방에 있는 메모리를 다시 올리게 됩니다. 이런식으로 하다보니 성능이 떨어지게 되는데 이러한 상황은 코어수가 올라갈수록 더 심해지게 됩니다.
그래서 데이터 로컬리티가 공짜 점심이 끝난 다음에 더 중요해지는데 좋은점은 ECS 구조로 가면 이 컴포넌트가 오로지 데이터만 가지고 있기 때문에 같은 컴포넌트는 같이 Array형태로 묶을 수가 있습니다.
그래서 여러개의 Drawing 컴포넌트를 만들어서 Array에 넣은 다음에 이 Array의 몇 번째만 이 Entity를 가지고 있냐만 표시하면 됩니다.
그럼 Render System입장에서는 이 Array에 접근해서 순차적으로 Array를 돌면서 그림만 그려주면 메모리가 순차적으로 Access되기 때문에 데이터 로컬리티가 좋아지고 한번에 캐시라인에 같이 올라가서 성능이 빨라지는 상황이 생깁니다.
이게 ECS의 가장 큰 장점인데 문제는 System이 오로지 1:1이 대응이 되면 문제가 없지만 현실은 그렇지 않습니다.
예를 들어서 Combat System이 있는데(항상 전투가 문제가 됩니다.) 전투는 여러가지가 복잡하게 걸려있다 가정하여 그 상황에서
버프 시스템이 있어서 누가 나한테 버프를 걸었다. 했을 때 Combat System이 어떤 버프정보를 가져와야 이 Combat System을 적용 할 것인데 그러니까 Combat System이 System간의 상호 통신도 간으해야 되고, 그 다음에 컴포넌트 간의 관계도 System과 컴포넌트와의 관계가 1:1관계가 아니라 1:N 관계로 늘어날 수 있는 상황이 됩니다. 그러면 컴포넌트 의존성이 생기게 되는데
예를 들면 A시스템이 C1 컴포넌트 C2 컴포넌트를 의존하고 있고, B시스템이 C2 컴포넌트와 C3 컴포넌트를 의존하는 상황이라고 보면 A 시스템이 이 둘 컴포넌트들을 잘 돌면서 자기것을 처리하는데 A가 C1과 C2를 다 쓰기 때문에 B는 A가 끝날 때까지 기다려야 되는 상황이 생길 수도 있게 됩니다.
의존성이 생기게 되는 것입니다. 이러한 문제들이 생길 수도 있고, A 시스템이 잘 처리하다가 B 시스템한테 뭔가 물어봐야 되는 상황도 생깁니다.
마찬가지로 Akka방식과 마찬가지로 메세지 처리가 가능한데 서로 다른 쓰레드에 돌고 있으니까 메세지 큐에 서로 질문하고 답하는 방식도 가능하게 됩니다.
정리하자면 ECS 구조는 테이터들을 어떤 기준을 통해 나누었고, Entity는 순수하게 컴포넌트들을 가지고 있고, 컴포넌트는 순수하게 데이터만 가지고 있고, 시스템은 순수하게 기능만 가지고 각각의 역할을 순수하게 나누면서 독립성이 생겨났고 데이터 로컬리티가 좋아졌고 시스템이 멀티 쓰레드가 될 수가 있었지만 문제는 시스템과 컴포넌트와의 의존성 관계가 1:N이 될 수 있고 시스템과 시스템간의 Interaction이 일어날 수 있다는 것입니다.
그래서 이런 상황에서 시스템과 멀티쓰레드를 하겠다면 컴포넌트 의존성을 풀어야 되고 시스템과 통신 방식에서 Akka방식에서 발생했던 문제가 발생하게 됩니다.
그렇게 되면 복잡도가 올라가고, 그 다음에 비동기로 처리하려다 보니까 어떤 타이밍 이슈가 생기는 상황이 됩니다.
그리고 ECS 구조는 아직 완성된 구조가 아닙니다. 나온지도 얼마 안됐고, 아직 복잡한 문제가 많이 있으며 사람들이 많이 얘기하는 구조입니다.
유니티 다음 버전에서 쓰겠다고 발표했고, 유니티 다음 버전에서 ECS가 어떻게 구현되어 있는지 보면 도움이 될 것입니다.
ECS 구조는 Render 때문에 더 많이 씁니다. Render의 데이터 로컬리티가 굉장히 중요하기 때문입니다.
사실 컴퓨터가 하는 일은 그림 그리는게 다 라고 보면 됩니다. 90% 이상의 성능은 드로잉에서 다 끝난다고 결정된다고 보면 되죠.
물론 BackEnd에서는 드로잉이 없지만 FrontEnd에서는 드로잉이 굉장히 중요하기 때문에 이 Render를 어떻게 잘하느냐, 이 Render를 빠르게 하느냐가 중요한데 빠르게 하는데 관건은 데이터 로컬리티가 좋아야 되고, 데이터 로컬리티가 좋아지려면 ECS구조가 데이터 로컬리티가 좋아지는 한 방법이다. 라고 볼 수가 있습니다.
'Networking' 카테고리의 다른 글
[바미] RTMP(Real Time Messge Protocol)란? (0) | 2022.10.30 |
---|---|
[바미] WebRTC, STUN서버, TURN서버에 대해 (0) | 2022.10.27 |
[바미] MMORPG 서버 구조에 대해 알아보자.(2)(싱글프로세스 vs 멀티프로세스) (1) | 2020.12.19 |
[바미] MMORPG 서버 구조에 대해 알아보자! (1) (3) | 2020.12.18 |
[바미] Socket Programming에 대해 알아보자! (0) | 2020.12.18 |