Como alguém deve lidar com o buffer intermediário da classe DataReader?

5

Resumo

Estou desenvolvendo um leitor de formato de arquivo WAV no WinRT e, para isso, preciso ler quantidades aleatórias de estruturas que consistem em tipos fundamentais, como int , uint , float e assim por diante.

De volta ao desenvolvimento de desktops, seria necessário BinaryReader , agora no WinRT ele foi substituído por DataReader que funciona de forma assíncrona.

Problema

Não consigo entender como usar essa nova classe desde agora, um buffer intermediário deve ser preenchido usando LoadAsync () , antes de chamar métodos de leitura, como ReadInt32 () .

Por outro lado, com o antigo BinaryReader não havia noção de ter que preencher um buffer intermediário antes de ler as primitivas da fonte.

Todos os exemplos que vi na Web são "ingênuos" no sentido de que eles lêem inteiramente o fluxo de origem na memória, mas, no meu caso, um arquivo WAV está no intervalo de cem megabytes e possivelmente gigabytes.

Eu esbocei os seguintes métodos auxiliares que pré-preenchem o buffer intermediário com apenas o que é necessário e basicamente me libera de chamar sistematicamente LoadAsync toda vez antes de ler algo do fluxo:

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();
    }
}

Mas não tenho certeza se esse é o caminho a percorrer quando usar DataReader .

Pergunta

Como se supõe que a pessoa preencha o buffer intermediário no meu caso?

  • deve-se carregar apenas a quantidade necessária, conforme mostrado acima?
  • ou deve-se carregar um tamanho constante (por exemplo, 65536 bytes), acompanhar a posição de leitura e, possivelmente, pré-buscar mais solicitações maiores? (basicamente envolvendo um DataReader em uma classe auxiliar)

EDITAR

Ao analisar o código-fonte do BinaryReader , não parece haver nenhum tipo de mágica atrás da cena, isto é, os bytes são buscados sob demanda. Então, no meu caso, mesmo que pareça um pouco bobo ler primitivos de forma assíncrona, acho que é a maneira mais simples e segura de fazer isso; em contraste com o empacotamento de DataReader , rastreamento da posição de leitura, manipulação de um buffer intermediário e, finalmente, a incapacidade de derivar dele como tipos WinRT públicos devem ser selados ... não tenho certeza se vale a pena pelo resultado.

Infelizmente fontes de assemblies WINMD estão indisponíveis, teria sido muito interessante ver como eles fazem isso na Microsoft como esses tipos mais recentes podem ser usados como tipos mais antigos, com estes métodos de extensão .

    
por Aybe 20.09.2015 / 23:23
fonte

1 resposta

3

should one load only the needed amount as shown above ?

Você deve carregar no buffer tudo o que você pode esperar para processar com o código que segue. No exemplo de documentação DataReader , eles lêem todo o fluxo no buffer, porque eles vão processar tudo imediatamente.

A razão para o buffer é que o IO é lento (geralmente). Portanto, a quantidade de dados especificada é carregada com E / S assíncrona no buffer de memória na frente. Então, você pode lê-lo subseqüentemente sem esperar por IO em todas as leituras. Isso é bom para o desempenho. O IO é em lote que melhorará o desempenho em muitos dispositivos (por exemplo, discos rígidos mecânicos). A execução do seu código está suspensa (devido a async / await) até que o pedido de inserção esteja terminado, por isso não está a ligar os ciclos da 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)

Às vezes, o tamanho dos dados será muito grande para ser carregado na memória de uma só vez. O próprio .NET define um limite de memória de 2 GB por objeto (). Portanto, se os dados que você está lendo estiverem próximos de 2 GB, você definitivamente desejará acompanhar a posição de leitura do fluxo e ler apenas parte do arquivo no buffer. Então, quando chegar ao fim do buffer, preencha-o novamente a partir da próxima posição de leitura e continue o processamento. Repetindo conforme necessário até que você processe o arquivo inteiro.

    
por 14.10.2015 / 22:54
fonte