Qual é o caminho mais rápido para leitura/escrita no disco .NET?
Pergunta
Tenho um pequeno programa que lê e grava arquivos no disco.Quebrá-lo para baixo para o nível mais simples, ele lê bytes de um fluxo de arquivos e grava-los para outra.Ele executa suas funções muito bem, mas ele não é a coisa mais rápida.
Eu já vi outros aplicativos que podem romper-se através de um ou mais gigabytes de leituras/gravações em velocidades incríveis.É óbvio que eles estão operando mais próximo do metal do que um pouco .NET app.
O que são as mais eficientes .APIs de rede para streaming de/para o disco?O que win32 APIs estão disponíveis (e vale p/a invocação para) para rápido acesso a disco?
Solução
Rápido e/S de arquivo é menos sobre o específico chamadas de API que você faz, mas sim sobre como você projetar seu aplicativo para trabalhar com I/O.
Se você estiver executando todas as suas operações de e/S em um único segmento de uma forma sequencial, por exemplo
- Bloco de leitura na memória
- Processo bloco de memória, de alguma forma,
- Bloco de gravação para arquivo
- Repita até terminar...
você está gargalos do sistema de e/S de largura de banda do loop de processamento de um único segmento.Uma alternativa, mas mais complicado design é multithread sua aplicação para maximizar a produtividade e evitar o tempo de espera.Isto permite que o sistema para aproveitar tanto o CPU e de e/S de largura de banda do controlador simultaneamente.Um típico projeto para este ficaria algo como:
- Um (ou mais) threads de trabalho de leitura de dados a partir do disco e adicioná-los a uma casa de fila de entrada
- Um (ou mais) threads de trabalho de leitura de blocos de partilhada fila de entrada, processá-los e adicioná-los a uma casa de fila de saída
- Um (ou mais) threads de trabalho de leitura processados bloqueado compartilhado fila de saída e escreve para o adequado arquivos de saída.
Isso não é fácil de arquitectura para o design de direito, e requer um pouco de pensamento para evitar a criação de memória de contenção de bloqueio, ou sobrecarregar o sistema com simultâneas solicitações de e/S.Você também precisará fornecer controle de metadados, de modo que o estado de processamento de saída não é gerenciado na pilha de chamada de uma linha, mas sim na entrada/saída de filas de trabalho.Você também tem que se certificar de que você transformação e escrever o resultado na ordem correta, pois com multi-thread de e/S que você não pode ter certeza de que o trabalho é colocado na fila de entrada em uma ordem garantida.É complicado, mas é possível, e ele pode ter uma diferença dramática na taxa de transferência através de uma série de abordagem.
Se você realmente tiver tempo e quiser espremer cada gota de desempenho do sistema, você também pode usar Conclusão de e/S portas - um relativamente baixo nível de API, para maximizar a taxa de transferência.
Boa sorte.
Outras dicas
O suporte do arquivo .NET é rápido o suficiente (comparável às funções nativas do Win32). Várias opções que podem ajudá -lo a melhorar seu desempenho:
- Se a sua leitura/gravação for seqüencial, ajude o gerente de cache aplicando a estratégia apropriada - forneça RandomAccess ou Sequentalscan, ao instanciar o FileStream
- Considere usar um buffer de memória maior para armazenar dados de leitura
- Se você copiar muitos arquivos pequenos, poderá primeiro ler muitos arquivos em um buffer de memória de uma só vez (consulte 2) e depois escreva os arquivos no disco
- Se os fluxos de origem e destino estiverem localizados em lugares diferentes (ou seja, não no mesmo disco rígido, talvez um arquivo na rede, o outro em um disco rígido local etc.), você pode usar o padrão assíncrono para acelerar , leia dados usando BEGIN LREAD, então escreva dados usando BeginWrite, e enquanto os dados estão sendo escritos, leia o próximo bloco de dados usando o BEGINRAD.
- Se você ainda acha que o desempenho não é suficiente (no entanto, do meu teste, é equatável ou ainda mais rápido que a cópia do Windows interna), você pode usar o CopyFileEx Função Win32 (mas essa função funciona com arquivos, não fluxos).
Você apresentou um perfil de seu aplicativo para determinar se a E/S do disco era o gargalo?
Em que tipo de hardware você está executando isso? Qual é a configuração de hardware?
Em .net você pode tentar o System.IO.File
espaço para nome.
Para funções Win32, você pode experimentar a série CreateFile, Writefile e ReadFile.
Um exemplo:
http://msdn.microsoft.com/en-us/library/bb540534(vs.85).aspx
Definitivamente, isso não é cortado e seco. É tudo sobre testar e medir.
BinaryReader
e BinaryWriter
Com um tamanho de buffer adequado, é muito rápido. Se você está lendo em estruturas, a abordagem insegura descrita neste artigo Vai fazer você ler rapidamente, e escrever é semelhante. Também concordo com a sugestão de verificar se a E/S é realmente o gargalo. Eu me deparei com esse artigo devido a esse erro.