Pergunta

Eu tenho uma aplicação que necessita para percorrer todas as linhas em arquivos de texto, mais de gigabytes de tamanho. Alguns desses arquivos têm 10 ou 100 de milhões de linhas.

Um exemplo de meu atual (e síncrona) lendo, é algo como ...

  using (FileStream stream = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.Read)) {
    using (StreamReader streamReader = new StreamReader(stream)) {
      string line;
      while (!string.IsNullOrEmpty(line = streamReader.ReadLine())) {           
        //do stuff with the line string...
      }
    }
  }

Eu tenho lido algumas coisas sobre o .NET Asynchronous IO métodos de streaming, e eu depois de alguma ajuda com 2 perguntas específicas sobre esta questão.

Em primeiro lugar, vou receber um aumento de desempenho através da leitura asyncronously esses arquivos, se eu preciso do entireity de cada linha, que são ussually curto, mas de comprimentos diferentes (não há relação entre cada uma das linhas no arquivo)?

Em segundo lugar, Como faço para converter o código acima, em uma leitura assíncrona, para que eu possa processar cada linha por linha, como eu faço agora?

Foi útil?

Solução

Em vez de fazer a linha lê Async que você pode tentar fazer o arquivo lê Async. Isso é abranger todo o código na sua pergunta em um único delegado dos trabalhadores.

    static void Main(string[] args)
    {
        WorkerDelegate worker = new WorkerDelegate(Worker);
        // Used for thread and result management.
        List<IAsyncResult> results = new List<IAsyncResult>();
        List<WaitHandle> waitHandles = new List<WaitHandle>();

        foreach (string file in Directory.GetFiles(args[0], "*.txt"))
        {
            // Start a new thread.
            IAsyncResult res = worker.BeginInvoke(file, null, null);
            // Store the IAsyncResult for that thread.
            results.Add(res);
            // Store the wait handle.
            waitHandles.Add(res.AsyncWaitHandle);
        }

        // Wait for all the threads to complete.
        WaitHandle.WaitAll(waitHandles.ToArray(), -1, false); // for < .Net 2.0 SP1 Compatibility

        // Gather all the results.
        foreach (IAsyncResult res in results)
        {
            try
            {
                worker.EndInvoke(res);
                // object result = worker.EndInvoke(res); // For a worker with a result.
            }
            catch (Exception ex)
            {
                // Something happened in the thread.
            }
        }
    }

    delegate void WorkerDelegate(string fileName);
    static void Worker(string fileName)
    {
        // Your code.
        using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            using (StreamReader streamReader = new StreamReader(stream))
            {
                string line;
                while (!string.IsNullOrEmpty(line = streamReader.ReadLine()))
                {
                    //do stuff with the line string...
                }
            }
        }
    }

Outras dicas

O padrão assíncrono é BeginRead () / EndRead ().

Se vai ou não receber um impulso depende muito sobre o que mais está acontecendo no momento que você está fazendo as leituras. Há outra coisa que seu aplicativo pode fazer enquanto espera a lê? Se não, então vai assíncrona não vai ajudar muito ...

Asynchronous lê só vai acabar fazendo a cabeça buscar mais para cada bloco. Você vai obter um melhor aumento de desempenho de uma boa desfragmentação dos arquivos no sistema de arquivos e usando leitura síncrona.

Como já salientado, despachando o processamento linha para outros tópicos devem dar um impulso (especialmente em CPUs multi-core)

Se o desempenho é super-crítica Eu recomendaria investigando interoperabilidade para FILE_FLAG_SEQUENTIAL_SCAN See detalhes aqui

Melhor ainda escrever aplicativos uma pequena C ++ que varre o arquivo com essa bandeira para ver se ele melhora o desempenho.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top