Come si dovrebbe gestire il buffer intermedio della classe DataReader?

5

Riepilogo

Sto sviluppando un lettore di file in formato WAV con WinRT, e per questo ho bisogno di leggere quantità casuali di strutture costituite da tipi fondamentali come int , uint , float e così via.

Indietro nello sviluppo del desktop ci si potrebbe basare su BinaryReader , ora in WinRT è stato sostituito da DataReader che funziona in modo asincrono.

problema

Non riesco a capire come usare questa nuova classe da ora, un buffer intermedio deve essere compilato usando LoadAsync () , metodi di lettura delle chiamate precedenti come ReadInt32 () .

Al contrario, con il vecchio BinaryReader non c'era la nozione di dover riempire un buffer intermedio prima di leggere le primitive dalla sorgente.

Ogni esempio che ho visto sul web sono "ingenui" nel senso che leggono interamente il flusso sorgente in memoria, ma nel mio caso un file WAV si trova nell'intervallo di cento megabyte e forse gigabyte.

Ho abbozzato i seguenti metodi di supporto che pre-riempiono il buffer intermedio con solo ciò che è necessario e in pratica mi libera dal chiamare sistematicamente LoadAsync ogni volta prima di leggere qualcosa dallo stream:

internal static class DataReaderExtensions
{
    public static async Task<string> ReadStringAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        return reader.ReadString(length);
    }

    private static async Task LoadAsync(DataReader reader, uint length)
    {
        var u = await reader.LoadAsync(length);
        if (u < length) throw new InvalidOperationException();
    }
}

Ma non sono completamente sicuro se sia la strada da percorrere quando si utilizza DataReader .

Domanda

Come si suppone di pre-riempire il buffer intermedio nel mio caso?

  • si dovrebbe caricare solo la quantità necessaria come mostrato sopra?
  • o si dovrebbe caricare una dimensione costante (ad esempio 65536 byte), tenere traccia della posizione di lettura quindi eventualmente pre-scaricare di più su richieste più grandi? (sostanzialmente avvolgendo DataReader in una classe helper)

Modifica

Guardando il codice sorgente di BinaryReader non sembra esserci alcun tipo di magic dietro la scena, ovvero i byte vengono scaricati su richiesta. Quindi per il mio caso, anche se sembra un po 'sciocco leggere le primitive in modo asincrono, immagino sia il modo più semplice e sicuro per farlo; a differenza del wrapping di DataReader , del rilevamento della posizione di lettura, della gestione di un buffer intermedio e infine l'impossibilità di derivarne come tipi WinRT pubblici devono essere sigillati ... non è sicuro che ne valga la pena per il risultato.

Purtroppo le origini degli assembly WINMD non sono disponibili, sarebbe stato piuttosto interessante vedere come lo fanno in Microsoft, poiché questi tipi più recenti possono essere utilizzati come tipi precedenti, con questi metodi di estensione .

    
posta Aybe 20.09.2015 - 23:23
fonte

1 risposta

3

should one load only the needed amount as shown above ?

Dovresti caricare nel buffer tutto ciò che puoi aspettarti di elaborare con il codice che segue. Nell'esempio di documentazione DataReader , hanno letto l'intero stream nel buffer, perché lo elaboreranno immediatamente.

Il motivo del buffer è che IO è lento (di solito). Quindi la quantità di dati specificata viene caricata con IO asincrono nel buffer di memoria in primo piano. Quindi puoi successivamente leggerlo senza aspettare IO su ogni lettura. Questa è una buona cosa per le prestazioni. L'I / O viene dosato, il che migliorerà la perfezione su molti dispositivi (ad esempio dischi rigidi meccanici). L'esecuzione del codice è sospesa (a causa di asincrona / attesa) fino al termine dell'IO, quindi non sta vincolando i cicli della CPU.

or should one load a constant size (e.g. 65536 bytes), keep track of reading position then possibly pre-fetch more on larger requests ? (basically wrapping a DataReader in a helper class)

A volte la dimensione dei dati sarà troppo grande per caricare in memoria tutto in una volta. .NET stesso imposta un limite di memoria di 2 GB per oggetto ( bene, sortof ). Quindi, se i dati che stai leggendo sono vicini a 2 GB, dovrai sicuramente tenere traccia della posizione di lettura del flusso e leggere solo parte del file nel buffer. Quindi, una volta arrivato alla fine del buffer, riempirlo nuovamente dalla successiva posizione di lettura e continuare l'elaborazione. Ripetendo se necessario finché non hai elaborato l'intero file.

    
risposta data 14.10.2015 - 22:54
fonte