Il caricamento lazy è sempre richiesto?

1

So che è necessario un caricamento lento quando viene effettuata una chiamata di database costosa. In questo esempio, avrebbe senso utilizzare il caricamento lazy. L'esempio di sotto è nel contesto di asp.net quindi è thread-safe.

private list<Customer> _AllCustomers;
public list<Customer> AllCustomers {
get {
    if (_AllCustomers == null) {
        _AllCustomers = ExpensiveDataCall();
    }

    return _Customers;
}
 }

Anche se si tratta solo di istanziare un oggetto che viene utilizzato in più punti, io uso sempre il caricamento lazy. Considera il seguente esempio:

private _Customer;
public Customer Customer {
get {
    if (_Customer == null) {
        _Customer = new Customer;
    }

    return _Customer;
}
 }

Recentemente qualcuno mi ha detto che il caricamento lento è richiesto solo per le costose chiamate al database. È giusto? Ho pensato che ogni volta che un oggetto viene istanziato, la memoria aumenta (scusati per la terminologia, non ho molte conoscenze tecniche.)

    
posta Howls Hagrid 04.04.2015 - 01:37
fonte

2 risposte

6

C'è un'altra cosa che potresti voler prendere in considerazione oltre al semplice fattore di velocità.

Il codice stesso. Ed è manutenibilità.

  • Questo tipo di caricamento lento rende il codice più lento da scrivere o più difficile da capire e modificare?
  • Rende l'architettura più complessa che deve essere?

Seguono alcuni esempi.

if (_AllCustomers == null) {
    _AllCustomers = ExpensiveDataCall();
}

return _AllCustomers; // Was: _Customers, not sure if by design.

Ora, pensa a uno scenario in cui hai già letto l'attributo AllCustomers una volta e poi hai apportato alcune modifiche che potrebbero riguardare tali dati. In che modo il chiamante ottiene un nuovo elenco di clienti se ne avesse bisogno?

Può in qualche modo forzare l'annullamento di _AllCustomers per far sì che il ExpensiveDataCall() si ripeta? Dovrebbe sapere anche che i dati di _AllCustomers potrebbero essere vecchi ormai?

Puoi sempre creare un metodo aggiuntivo RefreshAllCustomersData() o simile, ma che aggiunge la complessità del tuo codice.

Questo, ovviamente, potrebbe non essere un problema nella tua applicazione. Dipende dall'architettura generale. E anche se lo fosse, la soluzione per l'aggiornamento potrebbe essere molto adatta. È ancora qualcosa da considerare.

Anche scenari più semplici, come quello a cui realmente ti interessava, potrebbero creare un sovraccarico aggiuntivo per un programmatore, se non per l'applicazione stessa.

if (_Customer == null) {
    _Customer = new Customer;
}

return _Customer;

Cosa succede se un programmatore, facendo una lezione, dimentica accidentalmente di verificare la presenza di null e creare un nuovo oggetto, e restituisce solo null? Probabilmente non ci vorranno troppi secondi per accorgersene, ma potrebbe.

Quando si tratta di stili di codifica, questa è un'altra cosa da ricordare e applicare a ogni classe simile. Avere, ad esempio, solo un paio di classi di modelli che seguono questa convenzione, potrebbe essere fonte di confusione.

Inoltre, ci sono un paio di linee extra che forse potresti fare senza . Almeno, fino al punto in cui si esegue l'applicazione con il profiler e si noti che l'aggiunta di un caricamento lazy in determinate aree migliora davvero le prestazioni in modo evidente. Meno codice significa che c'è meno da leggere e meno da capire.

Tuttavia, come nel primo esempio, dipende anche la praticità di questo. Se sai che hai dei colpevoli delle prestazioni che vanno via facendo il pigro caricamento su alcune classi spesifiche, provaci.

È ancora utile misurare l'impatto che stanno facendo prima di prendere una decisione. E ogni volta che formi una solida convenzione, resta fedele ad essa.

tl; dr: mentre il caricamento lento è uno strumento utile per migliorare le prestazioni, non è sempre necessario. Questo perché ci sono anche altri fattori da considerare. Vale a dire, manutenibilità del codice.

    
risposta data 04.04.2015 - 03:37
fonte
3

IMHO Lazy loading è un modello nella tua lista di scelte progettuali. Non c'è "sempre" o "mai" .. più la domanda: quando dovrei e quando non dovrei.

Quando tornavo ad avere sempre il carico pigro per la maggior parte delle cose, oggigiorno lo uso raramente, preferendo invece caricare "una buona quantità" (più formalmente conosciuto come "contesto limitato") di diversi oggetti e dei loro associati raccolti (ad esempio, la fattura e i relativi elementi pubblicitari) sarebbero adatti per un singolo "grande carico" senza l'utilizzo di un carico pigro.

Detto questo, se sto costruendo un sistema di parti per un aereo, posso scegliere di caricare sottoinsiemi pigri se l'utente ha deciso che è necessario "approfondire ulteriormente" in ciò che li ho presentati sullo schermo piuttosto che attendere per tutti 100.000 parti da restituire prima che l'utente possa fare qualsiasi cosa.

Questo mi porta alle mie " regole empiriche ".

  • Se visualizzerò una schermata (o una pagina) di dati all'utente quando si caricheranno, eseguirò un "singolo grande colpo".
  • Se lo schermo abilita il drill down (come una vista ad albero o una lista a scorrimento), caricherò ciò che è visibile + 1 livello / schermo in modo che l'utente abbia qualche "gioco" quando inizia a scorrere o inizia a eseguire il drill down. Il prossimo blocco caricherò lentamente quando penso che l'utente abbia chiesto direttamente o sia "abbastanza vicino" da chiederglielo.

L'idea di base è che in media dovresti caricare quanti più dati possibile senza che l'utente si accorga che sono in attesa del caricamento dei dati (< 1 secondo è l'ideale).

Quando un utente non è coinvolto, la tua considerazione diventa "tempo di elaborazione complessivo" per un batch dall'origine (database) > caricamento > elaborazione > risultato finale > archiviazione o azione finale risultante. Vuoi caricare tanto quanto

Nel tuo esempio :

Caricare ogni cliente per un sistema di piccole imprese è probabilmente ok (< 100 o giù di lì) per prendere il colpo e farlo in anticipo, altrimenti mi piacerebbe caricare pigro.

Carico e singolo cliente, supponendo che ci sia una buona possibilità che verrà utilizzato dalla schermata / processo, lo farei in anticipo perché il trasferimento attraverso il filo due volte è più che altro un ritardo rispetto al caricamento del cliente insieme ad altre cose sul server.

La tua domanda : "consuma memoria"

Risposta : Sì, ogni variabile che usi consuma memoria (di solito non molto).

Migliori domande da porre :

  1. ti interessa la quantità di memoria che occupa più di avere le informazioni disponibili per l'utente senza ritardo?

Risposta : maggiore è la quantità di "materiale" caricato maggiore è la probabilità di utilizzare il caricamento lento.

  1. qual è il ritardo di tempo richiesto per eseguire il caricamento lento e viene eseguito in un punto in cui l'utente si preoccupa del tempo?

Risposta : per esempio Se mostri all'utente qualcosa come prima dell'intestazione o dei dettagli di riepilogo e poi carichi pigro in tutti i risultati dei dettagli, di solito l'utente non si preoccupa di aspettare. Se il tuo carico pigro in ogni ultimo oggetto, l'utente è in attesa del record del cliente + della specifica fattura a cui tengo + il totale del suo account + i record delle transazioni + gli elementi pubblicitari per la fattura, allora probabilmente sceglierai di inoltrare il carico + Fattura specifica + Totale del proprio account e poi pigro caricare i record delle transazioni ... gli elementi pubblicitari della fattura sarebbero una chiamata basata sul tuo caso d'uso in merito alla tua necessità di caricare pigro o di caricare in anticipo.

  1. quali sono i costi (memoria, ritardo, utilizzo della rete e del database) associati a un "carico"?

Risposta : dipende. Tutto su 1 macchina, probabilmente non importa molto, il numero di accessi al database sarà probabilmente il collo di bottiglia. Client / server è probabilmente il frame temporale della query del database, il server web è più probabile il trasferimento di rete seguito dal database che è il problema. Ciascuno sposterà i post degli obiettivi su dove i costi sono effettivamente necessari.

    
risposta data 07.04.2015 - 09:18
fonte

Leggi altre domande sui tag