La gestione non deterministica delle risorse è un'astrazione debole?

9

Da quello che vedo, ci sono due forme pervasive di gestione delle risorse: distruzione deterministica ed esplicita. Esempi del primo sarebbero i distruttori C ++ e i puntatori intelligenti o il sottotitolo DESTROY di Perl, mentre un esempio di quest'ultimo sarebbe il paradigma Blocks-to-manage-resources di Ruby o l'interfaccia IDispose di .NET.

Le lingue più recenti sembrano optare per queste ultime, forse come effetto collaterale dell'utilizzo dei sistemi di raccolta dei rifiuti della varietà di conteggio non di riferimento.

La mia domanda è questa: dato che i distruttori per puntatori intelligenti o sistemi di raccolta dei rifiuti con conteggio di riferimento - quasi la stessa cosa - consentono la distruzione di risorse implicite e trasparenti, è un'astrazione meno dispersiva rispetto ai tipi non deterministici che fare affidamento sulla notazione esplicita?

Darò un esempio concreto. Se si dispone di tre sottoclassi C ++ di una singola superclasse, è possibile che un'implementazione non richieda alcuna distruzione specifica. Forse fa la sua magia in un altro modo. Il fatto che non abbia bisogno di alcuna distruzione speciale è irrilevante - tutte le sottoclassi sono ancora utilizzate allo stesso modo.

Un altro esempio utilizza i blocchi Ruby. Due sottoclassi devono liberare risorse, quindi la superclasse opta per un'interfaccia che utilizza un blocco nel costruttore, anche se altre sottoclassi specifiche potrebbero non averne bisogno poiché non richiedono alcuna distruzione speciale.

È il caso che quest'ultimo presenti dettagli sull'implementazione della distruzione delle risorse, mentre il primo non lo fa?

MODIFICA: Confrontare, diciamo, Ruby con Perl potrebbe essere più giusto dal momento che uno ha una distruzione deterministica e l'altro no, eppure entrambi sono spazzati via.

    
posta Louis Jackman 12.03.2013 - 07:41
fonte

4 risposte

2

Il tuo esempio risponde alla domanda. La distruzione trasparente è chiaramente meno dispersiva della distruzione esplicita. Può perdere, ma è meno dispersivo.

La distruzione esplicita è analoga a malloc / free in C con tutte le insidie. Forse con un po 'di zucchero sintattico per farlo apparire basato sul campo.

Alcuni dei vantaggi della distruzione trasparente su esplicita:
--uso modello di utilizzo
- Non puoi dimenticare di rilasciare la risorsa.
- I dettagli precisi non sporcano il paesaggio nel punto di utilizzo.

    
risposta data 12.03.2013 - 19:33
fonte
2

Il fallimento nell'astrazione non è in realtà il fatto che la garbage collection sia non deterministica, ma piuttosto l'idea che gli oggetti siano "interessati" a cose a cui tengono riferimenti e non sono interessati alle cose a cui non tenere riferimenti Per capire perché, si consideri lo scenario di un oggetto che mantiene un contatore di quanto spesso viene dipinto un particolare controllo. Al momento della creazione, si abbona all'evento "paint" del controllo e al momento dell'eliminazione dell'iscrizione. L'evento click incrementa semplicemente un campo e un metodo getTotalClicks() restituisce il valore di quel campo.

Quando viene creato l'oggetto contatore, deve essere memorizzato un riferimento a se stesso all'interno del controllo che sta monitorando. Il controllo davvero non si preoccupa del contro oggetto, e sarebbe altrettanto felice se l'oggetto contatore, e il riferimento ad esso, cessasse di esistere, ma finché il riferimento esisterà chiamerà ogni volta quel gestore di eventi dell'oggetto si dipinge da solo Questa azione è totalmente inutile per il controllo, ma sarebbe utile a chiunque voglia chiamare getTotalClicks() sull'oggetto.

Se ad es. un metodo consisteva nel creare un nuovo oggetto "counter-counter", eseguire un'azione sul controllo, osservare quante volte il control- lo veniva ridipinto, e quindi abbandonare l'oggetto counter-counter, l'oggetto sarebbe rimasto iscritto all'evento anche se nessuno sarebbe mai importato se l'oggetto e tutti i riferimenti ad esso semplicemente svanissero. Gli oggetti non diventerebbero idonei per la raccolta, tuttavia, fino a quando il controllo stesso è. Se il metodo fosse uno che verrebbe invocato molte migliaia di volte nella vita del controllo [uno scenario plausibile], potrebbe causare un overflow di memoria, ma per il fatto che il costo delle invocazioni N sarebbe probabilmente O (N ^ 2) o O (N ^ 3) a meno che l'elaborazione dell'abbonamento fosse molto efficiente e la maggior parte delle operazioni non implicasse alcuna pittura.

Questo particolare scenario potrebbe essere gestito dando al controllo il mantenimento di un debole riferimento all'oggetto contatore piuttosto che a uno strong. Un modello di sottoscrizione debole è utile, ma non funziona nel caso generale. Supponiamo che invece di voler avere un oggetto che monitora un singolo tipo di evento da un singolo controllo, si volesse avere un oggetto logger di eventi che monitorava diversi controlli e il meccanismo di gestione degli eventi del sistema era tale che ogni controllo necessitava di un riferimento a un diverso oggetto logger di eventi. In tal caso, l'oggetto che collega un controllo al logger degli eventi deve rimanere attivo solo fino a quando entrambi il controllo viene monitorato e il logger degli eventi rimane utile. Se né il controllo né il logger degli eventi hanno un strong riferimento all'evento di collegamento, cesseranno di esistere anche se è ancora "utile". Se uno dei due tiene un evento strong, la durata dell'oggetto di collegamento può essere inutilmente estesa anche se l'altro muore.

Se nessun riferimento a un oggetto esiste da nessuna parte nell'universo, l'oggetto può essere considerato inutile ed eliminato dall'esistenza. Il fatto che esista un riferimento a un oggetto, tuttavia, non implica che l'oggetto sia "utile". In molti casi, l'effettiva utilità degli oggetti dipenderà dall'esistenza di riferimenti a altri oggetti che - dal punto di vista del GC - non hanno alcun rapporto con essi.

Se gli oggetti sono notificati in modo deterministico quando nessuno è interessato a loro, saranno in grado di utilizzare tali informazioni per assicurarsi che chiunque possa beneficiare di tale conoscenza sia informato. In assenza di tale notifica, tuttavia, non esiste un modo generale per determinare quali oggetti sono considerati "utili" se si conosce solo l'insieme di riferimenti esistenti e non il significato semantico associato a tali riferimenti. Pertanto, qualsiasi modello che presuppone che l'esistenza o la non esistenza di riferimenti sia sufficiente per la gestione automatica delle risorse sarebbe destinato a fallire anche se il GC potesse rilevare immediatamente l'abbandono dell'oggetto.

    
risposta data 10.03.2014 - 18:02
fonte
0

No "il distruttore, o altra interfaccia che dice" questa classe deve essere distrutta "è un contratto di tale interfaccia.Se si crea un sottotipo che non richiede una distruzione speciale sarei incline a considerare che una violazione del Principio di sostituzione di Liskov.

Per quanto riguarda C ++ rispetto ad altri, non c'è molta differenza. C ++ forza l'interfaccia su tutti i suoi oggetti. Le astrazioni non possono perdere quando sono richieste dalla lingua.

    
risposta data 12.03.2013 - 17:30
fonte
0

My question is this: given that destructors for smart pointers or reference-counting garbage collection systems -- almost being the same thing -- allow implicit and transparent resource destruction, is it a less leaky abstraction than the non-deterministic types which rely on explicit notation?

Il dover guardare i cicli a mano non è né implicito né trasparente. L'unica eccezione è un sistema di conteggio dei riferimenti con una lingua che vieta i cicli in base alla progettazione. Erlang potrebbe essere un esempio di tale sistema.

Quindi entrambi gli approcci perdono. La differenza principale è che i distruttori perdono ovunque in C ++, ma IDispose è molto raro su .NET.

    
risposta data 31.05.2015 - 10:35
fonte

Leggi altre domande sui tag