설정
엔터티가 일련의 속성 (동작이없는 순수한 데이터)을 가질 수있는 엔티티 구성 요소 아키텍처를 가지고 있으며 해당 데이터에서 작동하는 엔티티 논리를 실행하는 시스템이 있습니다. 본질적으로 다소 의사 코드에서 :
Entity
{
id;
map<id_type, Attribute> attributes;
}
System
{
update();
vector<Entity> entities;
}
일정한 속도로 모든 엔티티를 따라 이동하는 시스템은
MovementSystem extends System
{
update()
{
for each entity in entities
position = entity.attributes["position"];
position += vec3(1,1,1);
}
}
본질적으로 가능한 효율적으로 update ()를 병렬화하려고합니다. 이것은 전체 시스템을 병렬로 실행하거나 한 시스템의 각 update ()에 두 개의 구성 요소를 제공하여 다른 스레드가 동일한 시스템의 업데이트를 실행할 수 있지만 해당 시스템에 등록 된 엔티티의 다른 하위 집합에 대해 수행 할 수 있습니다.
문제
표시된 MovementSystem의 경우 병렬화는 간단합니다. 엔터티는 서로 의존하지 않고 공유 데이터를 수정하지 않기 때문에 모든 엔터티를 병렬로 이동할 수 있습니다.
그러나 이러한 시스템은 때때로 엔티티가 서로 동일한 시스템 내에서 서로 상호 작용 (데이터 읽기 / 쓰기)해야하지만 때로는 서로 다른 시스템간에 상호 작용해야합니다.
예를 들어, 물리 시스템에서 때로는 개체가 서로 상호 작용할 수 있습니다. 두 객체가 충돌하여 위치, 속도 및 기타 속성을 읽고 업데이트 한 다음 업데이트 된 속성을 두 엔터티에 다시 씁니다.
엔진의 렌더링 시스템이 엔티티 렌더링을 시작하기 전에 다른 시스템이 실행을 완료하여 모든 관련 속성이 필요한지 확인해야합니다.
우리가 이것을 맹목적으로 병렬화하려고 시도하면 다른 시스템이 동시에 데이터를 읽고 수정할 수있는 고전적인 경쟁 조건으로 이어질 것입니다.
이상적으로는 다른 시스템이 동일한 데이터를 동시에 수정하는 것에 대해 걱정할 필요없이 프로그래머가 원하는 실행 및 병렬화를 적절히 순서화 할 필요없이 모든 시스템이 원하는 엔티티로부터 데이터를 읽을 수있는 솔루션이 존재합니다. 이러한 시스템을 수동으로 (때로는 불가능할 수도 있음).
기본 구현에서는 모든 데이터 읽기 및 쓰기를 중요한 섹션에 넣는 것 (뮤텍스로 보호)을 통해 달성 할 수 있습니다. 그러나 이로 인해 많은 양의 런타임 오버 헤드가 발생하며 성능에 민감한 응용 프로그램에는 적합하지 않을 수 있습니다.
해결책?
내 생각에 가능한 해결책은 데이터 읽기 / 업데이트 및 쓰기가 분리 된 시스템이므로 하나의 비싼 단계에서 시스템은 데이터를 읽고 계산 해야하는 것을 계산하고 결과를 캐시 한 다음 모든 것을 쓸 수 있습니다. 변경된 데이터는 별도의 쓰기 패스로 대상 엔터티로 다시 전달됩니다. 모든 시스템은 데이터가 프레임의 시작 부분에 있던 상태에서 데이터에 대해 작동 한 다음 프레임이 끝나기 전에 모든 시스템의 업데이트가 완료되면 직렬화 된 쓰기 패스가 발생합니다. 시스템은 대상 엔티티를 통해 반복되어 다시 작성됩니다.
이것은 쉬운 병렬화 승리가 결과 캐싱 및 쓰기 패스의 비용 (런타임 성능 및 코드 오버 헤드 측면에서)을 능가 할만큼 충분히 클 수 있다는 아이디어를 기반으로합니다.
질문
최적의 성능을 달성하기 위해 그러한 시스템을 어떻게 구현할 수 있습니까? 이러한 시스템의 구현 세부 사항은 무엇이며이 솔루션을 사용하려는 엔티티 구성 요소 시스템의 전제 조건은 무엇입니까?