Domanda

Attualmente sto imparando la programmazione funzionale nel mio tempo libero con Scala, e ho una domanda da principiante inattivo.

Riesco a vedere l'eleganza di avere oggetti immutabili quando faccio qualcosa come calcolare una trasformazione wavelet di Haar, cioè quando i dati stessi rappresentati dagli oggetti non cambiano.

Ma ho visto un blog in cui qualcuno aveva un piccolo gioco come esempio per dimostrare l'immutabilità. Se un oggetto creatura ha ricevuto danno, non ha cambiato il suo stato - ha restituito un nuovo oggetto creatura con i nuovi punti ferita e un nuovo "aggro verso X" bandiera. Ma se dovessimo progettare qualcosa come un MMORPG, afferma World of Warcraft. Un centinaio di giocatori in un campo di battaglia ... forse migliaia di attacchi e effetti di incantesimi di buffering / debuff che li riguardano in diversi modi. È ancora possibile progettare il sistema con oggetti completamente immutabili? A me sembrerebbe che ci sarebbe un enorme sciame di nuove istanze ogni "tick". E per ottenere l'istanza di oggetti attualmente valida, tutti i clienti dovrebbero costantemente passare attraverso una sorta di "mondo di gioco" centrale oggetto o?

La programmazione funzionale si adatta a questo, o è un caso del "miglior strumento per il miglior lavoro, probabilmente non immutabile qui"?

È stato utile?

Soluzione

  

A me sembrerebbe che ci sarebbe uno sciame enorme di nuove istanze ogni 'tick'.

In effetti, è così. Ho un'applicazione Haskell che legge un feed di dati di mercato (circa cinque milioni di messaggi nel corso di una giornata di trading di sei ore, per i dati a cui siamo interessati) e mantiene "lo stato corrente". per varie cose, come l'offerta più recente e i prezzi e le quantità di offerta per gli strumenti, quanto il nostro modello si adatta al mercato, ecc. ecc. È piuttosto spaventoso simulare una corsa di questo programma contro un feed registrato in modalità di profilazione e guardare alloca e GC vicino a 288 TB di memoria (o quasi 50.000 volte la dimensione della RAM della mia macchina) nei primi 500 secondi della sua corsa. (La cifra sarebbe considerevolmente più alta senza profilazione, poiché la profilazione non solo rallenta l'applicazione, ma costringe anche tutto a funzionare su un solo core.)

Ma tieni presente che il garbage collector nelle implementazioni di linguaggio puro è ottimizzato per questo tipo di comportamento. Sono abbastanza soddisfatto della velocità complessiva della mia applicazione e penso che sia abbastanza impegnativo, in quanto dobbiamo analizzare diverse centinaia di messaggi al secondo dal feed di mercato, fare alcuni calcoli abbastanza estesi per costruire il nostro modello e usarlo modello per generare ordini per andare in borsa il più rapidamente possibile.

Altri suggerimenti

In genere nella programmazione funzionale non si avranno costruttori in stile C ++. Quindi, anche se concettualmente stai creando oggetti per tutto il tempo, ciò non significa che il compilatore debba creare codice per allocare un nuovo oggetto, perché non può influenzare il comportamento del programma. Poiché i dati sono immutabili, il compilatore può vedere quali valori hai appena specificato e quali sono stati passati alle tue funzioni.

Quindi, il compilatore può creare un codice compilato molto stretto che calcola semplicemente i campi negli oggetti specifici quando sono necessari. Quanto bene funziona dipende dalla qualità del compilatore che usi. Tuttavia, un codice di programmazione funzionale pulito dice al compilatore molto di più sul tuo codice di quanto potrebbe supporre un compilatore C per un programma simile, quindi un buon compilatore potrebbe generare un codice migliore di quello che ti aspetteresti.

Quindi, almeno in teoria, non c'è motivo di preoccuparsi; le implementazioni di programmazione funzionale possono essere ridimensionate così come implementazioni di allocazione di heap orientate agli oggetti. In pratica, devi comprendere la qualità dell'implementazione della lingua con cui stai lavorando.

Un MMORPG è già un esempio di immutabilità. Poiché il gioco è distribuito su server e sistemi di giocatori, non esiste assolutamente un "mondo di gioco" centrale oggetto. Pertanto, qualsiasi oggetto che viene inviato tramite il cavo è immutabile & # 8212; perché non viene modificato dal ricevitore. Invece, un nuovo oggetto o messaggio viene inviato come risposta, se presente.

Non ho mai scritto un gioco distribuito, quindi non so esattamente come siano implementate, ma sospetto che gli aggiornamenti agli oggetti siano calcolati localmente o inviati come diff sul filo.

Ad esempio, stai giocando a Command & amp; Conquistare. Il tuo mastodontico carro armato è seduto in modalità pronto a proteggere la tua base. Il tuo avversario si avvicina con un carro armato leggero per esplorare la tua base. Il tuo gigantesco carro armato spara e colpisce il carro del tuo avversario, causando danni.

Questo gioco è piuttosto semplice, quindi sospetto che molto sia calcolato localmente quando possibile. Supponiamo che i computer dei due giocatori siano inizialmente sincronizzati in termini di stato del gioco. Quindi il tuo avversario fa clic per spostare il suo carro armato leggero nella tua base. Un messaggio (immutabile) ti viene inviato via cavo. Poiché l'algoritmo per spostare un carro armato è (probabilmente) deterministico, la tua copia di Command & amp; Conquer può spostare il carro armato del tuo avversario sullo schermo, aggiornando il tuo stato di gioco (potrebbe essere immutabile o mutabile). Quando il serbatoio leggero arriva nel raggio d'azione del tuo serbatoio gigantesco, il serbatoio si spara. Un valore casuale viene generato sul server (in questo caso, un computer viene scelto arbitrariamente come server) per determinare se il tiro colpisce il tuo avversario o meno. Supponendo che il carro armato sia stato colpito e che debba essere effettuato un aggiornamento del carro armato del tuo avversario, solo il diff & # 8212; il fatto che il nuovo livello di armatura del carro armato sia sceso al 22% & # 8212; viene inviato tramite cavo per sincronizzare le partite dei due giocatori. Questo messaggio è immutabile.

Se l'oggetto sul computer di entrambi i giocatori che rappresenta il carro armato è mutabile o immutabile è irrilevante; può essere implementato in entrambi i modi. Ogni giocatore non cambia direttamente lo stato del gioco degli altri giocatori.

Un punto da notare sull'immutabilità è che (se implementato correttamente) rende la creazione di oggetti relativamente leggera. Se un campo è immutabile, può essere condiviso tra istanze.

È importante considerare quando si progetta un programma funzionale che, come si afferma, gli oggetti immutabili avranno un certo sovraccarico. È anche importante ricordare che avendo oggetti nel tuo programma MMORPG immutabili sarà intrinsecamente più scalabile. Pertanto, l'investimento iniziale in attrezzature potrebbe essere più elevato, ma lungo la strada man mano che le cose si espandono sarai in grado di ridimensionare alla base di giocatori.

Un'altra cosa importante da considerare è che in questo momento le macchine più alte hanno 6 core per CPU. Prendi in considerazione una doppia CPU con 6 core ciascuno. Uno di questi 12 core può eseguire la garbage collection e quindi il sovraccarico dovuto alla demolizione di molti oggetti può essere compensato dall'applicazione essendo facilmente scalabile rispetto agli altri 11 core.

Ricorda inoltre che non tutti gli oggetti (e i relativi oggetti secondari) devono essere completamente ricostruiti su una copia. Qualsiasi tipo di riferimento che non è cambiato prenderà una sola assegnazione di riferimento quando un oggetto viene "copiato".

Non pensare alla creazione di oggetti a livello di filo. Ad esempio, un runtime ottimizzato per un linguaggio funzionale sarà probabilmente in grado di "imbrogliare" quando si tratta di sostituire un oggetto e fare effettivamente una mutazione della struttura esistente, se non sa nulla farà riferimento all'originale e il nuovo lo sostituirà completamente. Pensa all'ottimizzazione della ricorsione della coda, ma applicata allo stato dell'oggetto.

Oggi ho trovato un blog che tratta ESATTAMENTE delle domande che ho sollevato in questo post:

http://prog21.dadgum.com/23.html

Come praticamente tutti gli strumenti di programmazione, gli oggetti immutabili sono potenti, ma pericolosi nella situazione sbagliata. Penso che l'esempio di gioco non sia molto buono o almeno molto inventato.

Eric Lippert ha alcuni interessanti post sull'argomento di immutabilità, e sono una lettura piuttosto interessante.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top