Perché Unity utilizza la reflection per ottenere il metodo di aggiornamento?


12

Perché l'Unità uso di riflessione al fine di accesso MonoBehaviourmetodi di messaggi come Awake, Update, Start, ...?

Non sarebbe lento usare la riflessione? Perché non sfrutta altri approcci come Template Method? Potrebbe semplicemente definire i metodi come astratti nella MonoBehaviourclasse base e forzare le sottoclassi a implementarlo.

Risposte:


20

Non

Come si chiama Update

No, Unity non utilizza System.Reflection per trovare un metodo magico ogni volta che deve chiamarne uno.

Invece, la prima volta che si accede a un MonoBehaviour di un determinato tipo, lo script sottostante viene ispezionato tramite il runtime di script (Mono o IL2CPP), indipendentemente dal fatto che abbia dei metodi magici definiti e che queste informazioni vengano memorizzate nella cache. Se un MonoBehaviour ha un metodo specifico, viene aggiunto a un elenco corretto, ad esempio se uno script ha definito il metodo di aggiornamento, viene aggiunto a un elenco di script che devono essere aggiornati ogni frame.

Durante il gioco Unity scorre semplicemente queste liste ed esegue i metodi da essa - così semplice. Inoltre, questo è il motivo per cui non importa se il metodo di aggiornamento è pubblico o privato.

Per quanto riguarda i motivi per cui viene fatto in questo modo, farò riferimento in gran parte (il lettore) alla risposta di DMGregory , che si riduce a un equilibrio di due cose in competizione:

  1. Ottimizzazione delle prestazioni
  2. Facilità di utilizzo di nuovi sviluppatori

Un nuovo sviluppatore vuole solo che funzioni e non vuole capire "come posso collegarlo al sistema degli eventi?" ma dovrebbe comunque funzionare velocemente con un sovraccarico minimo.

La soluzione è probabilmente la migliore che si può ottenere entro questi due vincoli. O almeno, il meglio che il team di sviluppo Unity è stato in grado di inventare in quel momento. Forse non lo sapremo mai.


2
tl; dr stesso processo, API diversa, più veloce. Ma perché non hanno scelto un metodo diverso come richiesto dall'OP?
Wondra,

10
Non dovremmo negare la possibilità di una semplice ragione "cattiva progettazione". Dopo il rilascio del codice sorgente c # , gli utenti hanno trovato tonnellate di errori e decisioni di progettazione inspiegabili. Alcuni Gamedev sono stati finalmente in grado di capire quei comportamenti inaspettati con cui hanno combattuto per anni.
Esercizio

I tecnicismi a parte questo sono tra le prime cose che i nuovi arrivati ​​imparano, quindi deve essere facile aggiungere o saltare.
Nikaas,

6
Potrebbero esserci anche ragioni storiche per questo design. Unity ha iniziato con il proprio linguaggio di scripting, che è stato gradualmente eliminato a favore di C #. È naturale che volessero continuare a usare gli stessi schemi, anche se significava imbrogliare un po '.
Philipp,

3
Penso che possiamo utilmente rispondere "Che cosa fa l'Unità con questo mezzo" - ad es. qual è il vantaggio rispetto a una raccolta di metodi pubblici astratti che devono essere tutti implementati. Non possiamo rispondere "cosa stavano pensando gli sviluppatori Unity?" ma possiamo affrontare "perché questo approccio è utile per gli utenti del motore?"
DMGregory

10

Potrebbe semplicemente definire i metodi come astratti nella classe base MonoBehaviour e forzare le sottoclassi per implementarlo.

Uno dei vantaggi del sistema utilizzato da Unity è che non è necessario implementare tutti i messaggi MonoBehaviour, di cui sono oltre 60 .

Di solito abbiamo solo bisogno di uno o una manciata di questi metodi. Dato che alcuni sono specifici della fisica 2D / 3D, altri specifici per le telecamere o i sistemi di particelle, è altamente improbabile che uno script possa mai averne bisogno.

Lasciando i messaggi di cui non abbiamo bisogno come non implementati, possiamo chiaramente segnalare al runtime "non preoccuparti nemmeno di chiamare OnCollisionStay2D su questo oggetto - non ne ho bisogno"

Questa può essere una vittoria di efficienza sostanziale. Ora il motore può filtrare un elenco ristretto per chiamare Aggiorna solo sugli ~ 20 oggetti nella mia scena che richiedono una logica di aggiornamento personalizzata per ogni fotogramma e non tutti i ~ 200 oggetti che compongono tutto lo scenario o rispondono solo agli eventi di fisica.


Solo una domanda ... per quanto ne so (non personalmente), se hai migliaia di GameObjects, ognuno dei quali utilizza uno script con un metodo di aggiornamento, hai un impatto significativo sulle prestazioni. L'alternativa è usare gli elenchi e scorrere attraverso di essi con un solo metodo di aggiornamento in uno script del gestore, che sembra essere significativamente più performante. È ancora così o è già cambiato? - Se non fosse cambiato nulla, ciò implicherebbe che il modo di Unity di farlo non è affatto ottimale per quanto riguarda le prestazioni.
Battaglia

4
@Battle quello che descrivi è coerente con il link che Draco18s cita dal 2015 e sospetto che sia ancora vero. Essere in grado di lasciare indefinito il metodo di aggiornamento su quelle migliaia di oggetti è esattamente ciò che consente a questa ottimizzazione di funzionare. Se ogni MonoBehaviour avesse un metodo di aggiornamento definito tramite una classe base astratta come descritto nella sezione della domanda che ho citato, allora non avremmo la possibilità di limitare le nostre chiamate di aggiornamento solo all'iterazione dell'elenco del gestore. Si noti che queste domande e risposte non riguardano "L'approccio di Unity è ottimale?" ma solo come l'approccio attuale può essere di beneficio.
DMGregory

Ah, vedo, ha davvero senso. Grazie per la risposta!
Battaglia

@Battle È ancora vero. Mentre la cosa che fa Unity è più performante delle alternative, ha ancora più spese generali di una normale chiamata di funzione.
Draco18s non si fida più di SE

@ Draco18s - Sì. Ho già implementato un UpdateManager per i miei progetti che si occupa di tale ottimizzazione molto tempo fa. Volevo solo qualche conferma che fosse ancora necessario / utile.
Battaglia
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.