Mempersiapkan
Saya memiliki arsitektur entitas-komponen di mana Entitas dapat memiliki sekumpulan atribut (yang merupakan data murni tanpa perilaku) dan terdapat sistem yang menjalankan logika entitas yang bertindak atas data tersebut. Pada dasarnya, dalam kode yang agak pseudo:
Entity
{
id;
map<id_type, Attribute> attributes;
}
System
{
update();
vector<Entity> entities;
}
Suatu sistem yang hanya bergerak sepanjang semua entitas dengan laju yang konstan mungkin
MovementSystem extends System
{
update()
{
for each entity in entities
position = entity.attributes["position"];
position += vec3(1,1,1);
}
}
Pada dasarnya, saya mencoba memparalelkan pembaruan () seefisien mungkin. Ini dapat dilakukan dengan menjalankan seluruh sistem secara paralel, atau dengan memberikan setiap pembaruan () dari satu sistem beberapa komponen sehingga utas yang berbeda dapat menjalankan pembaruan dari sistem yang sama, tetapi untuk subset entitas yang berbeda yang terdaftar dengan sistem itu.
Masalah
Dalam kasus MotionSystem yang ditampilkan, paralelisasi adalah sepele. Karena entitas tidak saling bergantung, dan tidak mengubah data yang dibagikan, kami bisa memindahkan semua entitas secara paralel.
Namun, sistem ini kadang-kadang mengharuskan entitas berinteraksi (membaca / menulis data dari / ke) satu sama lain, kadang-kadang dalam sistem yang sama, tetapi sering antara sistem yang berbeda yang saling bergantung.
Sebagai contoh, dalam sistem fisika terkadang entitas dapat berinteraksi satu sama lain. Dua objek bertabrakan, posisi mereka, kecepatan dan atribut lainnya dibaca dari mereka, diperbarui, dan kemudian atribut yang diperbarui ditulis kembali ke kedua entitas.
Dan sebelum sistem rendering di engine dapat memulai rendering entitas, ia harus menunggu sistem lain untuk menyelesaikan eksekusi untuk memastikan bahwa semua atribut yang relevan adalah yang mereka butuhkan.
Jika kita mencoba untuk memaralelkan ini secara membabi buta, itu akan mengarah pada kondisi balapan klasik di mana sistem yang berbeda dapat membaca dan memodifikasi data pada saat yang sama.
Idealnya, akan ada solusi di mana semua sistem dapat membaca data dari entitas apa pun yang diinginkannya, tanpa harus khawatir tentang sistem lain yang memodifikasi data yang sama pada saat yang sama, dan tanpa memiliki programmer yang peduli dengan benar memesan eksekusi dan paralelisasi dari sistem ini secara manual (yang kadang-kadang bahkan tidak mungkin).
Dalam implementasi dasar, ini dapat dicapai dengan hanya menempatkan semua data membaca dan menulis di bagian-bagian penting (menjaganya dengan mutex). Tapi ini menginduksi sejumlah besar overhead runtime dan mungkin tidak cocok untuk aplikasi yang sensitif terhadap kinerja.
Larutan?
Dalam pemikiran saya, solusi yang mungkin adalah sistem di mana membaca / memperbarui dan menulis data dipisahkan, sehingga dalam satu fase mahal, sistem hanya membaca data dan menghitung apa yang mereka butuhkan untuk menghitung, entah bagaimana menyimpan hasil, dan kemudian menulis semua data yang diubah kembali ke entitas target dalam tulisan yang terpisah. Semua sistem akan bertindak pada data di negara bagian itu berada di awal frame, dan kemudian sebelum akhir frame, ketika semua sistem telah selesai memperbarui, pass tulisan serial terjadi di mana hasil cache dari semua yang berbeda sistem diulangi dan ditulis kembali ke entitas target.
Ini didasarkan pada (mungkin salah?) Gagasan bahwa kemenangan paralelisasi mudah bisa cukup besar untuk mengalahkan biaya (baik dalam hal kinerja runtime serta overhead kode) dari hasil caching dan pass penulisan.
Pertanyaan
Bagaimana sistem seperti itu diimplementasikan untuk mencapai kinerja yang optimal? Apa rincian implementasi sistem seperti itu dan apa prasyarat untuk sistem Entity-Component yang ingin menggunakan solusi ini?