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?
sumber
Saya telah mendengar solusi menarik untuk masalah ini: Idenya adalah bahwa akan ada 2 salinan data entitas (boros, saya tahu). Satu salinan akan menjadi salinan saat ini, dan yang lainnya akan menjadi salinan sebelumnya. Salinan ini hanya ditulis, dan salinan yang lalu hanya dibaca dengan ketat. Saya berasumsi bahwa sistem tidak ingin menulis ke elemen data yang sama, tetapi jika itu tidak terjadi, sistem tersebut harus berada di utas yang sama. Setiap utas akan memiliki akses tulis ke salinan saat ini dari bagian data yang saling eksklusif, dan setiap utas memiliki akses baca ke semua salinan data yang lalu, dan dengan demikian dapat memperbarui salinan ini menggunakan data dari salinan sebelumnya tanpa mengunci. Di antara setiap bingkai, salinan saat ini menjadi salinan masa lalu, namun Anda ingin menangani pertukaran peran.
Metode ini juga menghilangkan kondisi balapan karena semua sistem akan bekerja dengan status basi yang tidak akan berubah sebelum / setelah sistem memprosesnya.
sumber
Saya tahu 3 desain perangkat lunak menangani pemrosesan data secara paralel:
Berikut beberapa contoh untuk setiap pendekatan yang dapat digunakan dalam sistem entitas:
CollisionSystem
yang membacaPosition
danRigidBody
komponen dan harus memperbaruiVelocity
. Alih-alih memanipulasiVelocity
secara langsung,CollisionSystem
malah akan menempatkanCollisionEvent
dalam antrian kerja dari sebuahEventSystem
. Acara ini kemudian akan diproses secara berurutan dengan pembaruan lainnya keVelocity
.EntitySystem
mendefinisikan seperangkat komponen yang perlu dibaca dan ditulis. Untuk masing-masingEntity
akan memperoleh kunci baca untuk setiap komponen yang ingin dibaca, dan kunci tulis untuk setiap komponen yang ingin diperbarui. Seperti ini, setiap orangEntitySystem
akan dapat membaca komponen secara bersamaan saat operasi pembaruan disinkronkan.MovementSystem
,Position
komponen tidak dapat diubah dan berisi nomor revisi . TheMovementSystem
savely membacaPosition
danVelocity
komponen dan menghitung baruPosition
, incrementing membaca revisi jumlah dan mencoba memperbaruiPosition
komponen. Dalam hal modifikasi bersamaan, kerangka kerja menunjukkan ini pada pembaruan danEntity
akan dimasukkan kembali dalam daftar entitas yang harus diperbarui olehMovementSystem
.Bergantung pada sistem, entitas, dan interval pembaruan, setiap pendekatan mungkin baik atau buruk. Kerangka kerja sistem entitas memungkinkan pengguna untuk memilih di antara opsi-opsi itu untuk mengubah kinerja.
Saya harap saya dapat menambahkan beberapa ide ke dalam diskusi dan beri tahu saya jika ada berita tentangnya.
sumber