Pregunta

Tengo una aplicación que necesita recorrer todas las líneas en archivos de texto, sobre un tamaño de gigabytes. Algunos de estos archivos tienen 10 o 100 millones de líneas.

Un ejemplo de mi lectura actual (y sincrónica), se parece a ...

  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...
      }
    }
  }

He leído algunas cosas sobre los métodos de transmisión de E / S asíncronas .Net, y estoy buscando ayuda con 2 preguntas específicas relacionadas con este problema.

Primero, ¿obtendré un aumento de rendimiento al leer estos archivos de forma asincrónica, si necesito la totalidad de cada línea, que generalmente es corta, pero de longitud variable (no hay relación entre cada una de las líneas en el archivo)?

Segundo, ¿cómo convierto el código anterior en una lectura asíncrona, para que pueda procesar cada línea por línea, como hago ahora?

¿Fue útil?

Solución

En lugar de hacer que la línea lea Async, puede intentar hacer que el archivo lea Async. Esto abarca todo el código de su pregunta en un solo delegado de trabajo.

    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...
                }
            }
        }
    }

Otros consejos

El patrón asíncrono es BeginRead () / EndRead ().

Si obtiene un impulso o no, depende mucho de lo que esté sucediendo en el momento en que realice las lecturas. ¿Hay algo más que su aplicación pueda hacer mientras espera en las lecturas? Si no, entonces ir asíncrono no ayudará mucho ...

Las lecturas asíncronas terminarán haciendo que la cabeza busque más para cada bloque. Obtendrá un mejor aumento de rendimiento de una buena desfragmentación de los archivos en el sistema de archivos y el uso de lectura síncrona.

Como ya se señaló, el envío del procesamiento de línea a otros subprocesos debería dar un impulso (especialmente en las CPU de varios núcleos)

Si el rendimiento es supercrítico, recomendaría investigar la interoperabilidad para FILE_FLAG_SEQUENTIAL_SCAN Ver detalles aquí

Mejor aún, escriba una pequeña aplicación de C ++ que explore el archivo con ese indicador para ver si mejora el rendimiento.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top