Automatic job dependency management
自動管理Job依賴。
管理Job的依賴是件很麻煩的事。而JobComponentSystem幫我們自動處理了。規則很簡單:不同系統的Jobs可以并行地通路同樣類型的IComponentData。但是如果有一個Job在向該資料寫操作,則這些Jobs不能并行執行,必須根據依賴排程Jobs。
public class RotationSpeedSystem : JobComponentSystem
{
[BurstCompile]
struct RotationSpeedRotation : IJobForEach<Rotation, RotationSpeed>
{
public float dt;
public void Execute(ref Rotation rotation, [ReadOnly]ref RotationSpeed speed)
{
rotation.value = math.mul(math.normalize(rotation.value), quaternion.axisAngle(math.up(), speed.speed * dt));
}
}
// Any previously scheduled jobs reading/writing from Rotation or writing to RotationSpeed
// will automatically be included in the inputDeps dependency.
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
var job = new RotationSpeedRotation() { dt = Time.deltaTime };
return job.Schedule(this, inputDeps);
}
}
How does this work?
所有這些Jobs和Systems聲明了它們要讀或寫的ComponentType,是以當JobComponentSystem傳回JobHandle時,它自動将對這些ComponentType的讀寫通路注冊到EntityManager中。
是以當一個系統向A寫操作,其它系統之後讀取A,那麼JobComponentSystem會檢查清單中的讀取操作,并将傳遞一個對第一個系統的依賴。
JobComponentSystem簡單地将Jobs按照依賴關系連接配接到一起,簡化了我們在主線程中的依賴關系管理。但是,如果一個非Job的ComponentSystem要通路這些資料呢?因為所有的資料通路時事先聲明好的,是以ComponentSystem會在與其它有共同依賴的component的所有的jobs完成後,再調用它的OnUpdate。
Dependency management is conservative & deterministic
依賴管理是保守且确定的
依賴管理傾向于保守。ComponentSystem簡單地跟蹤用到過的EntityQuery對象并記錄它們對元件類型的讀寫配置。
而且,當在一個System中排程多個jobs時,無論這些Jobs是否是依賴的,都要講依賴對象傳遞給它們。如果證明這導緻效率問題,那麼嘗試把該系統拆分成2個系統。
依賴管理被設計的保守,這樣能夠用簡單的API保證邏輯的确定性和正确性。
Sync points
所有對結構的改變,都會導緻“強制同步點”,如,CreateEntity,Instantiate,Destroy,AddComponent,RemoveComponent,SetSharedComponentData。這意味着這些調用發生時,之前通過JobComponentSystem排程的所有的Jobs都要完成。這是自動的。比如,在邏輯幀的執行中間,調用EntityManager.CreateEntity,會導緻邏輯停下來,等待之前的Jobs 完成。
可以通過EntityCommandBuffer來避免實體建立類操作導緻的Sync Points。
Multiple Worlds
每個World都有自己的EntityManager,以及互相獨立的JobHandle依賴管理。一個World的Hard Sync Point,不會對另一個World産生影響。是以,對于序列化和建立對象,一個有用的建議是,在一個World中建立對象,建立好後,在一幀的開始将他們移動到另一個World中。
可以參考System update order 以及 ExclusiveEntityTransaction來避免實體建立和序列化導緻的Sync Points。