Domanda

Ho un'applicazione che deve scorrere tutte le righe nei file di testo, con dimensioni superiori a gigabyte. Alcuni di questi file hanno 10 o 100 di milioni di righe.

Un esempio della mia lettura attuale (e sincrona), assomiglia 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...
      }
    }
  }

Ho letto alcune informazioni sui metodi di streaming IO asincrono .Net e sto cercando aiuto con 2 domande specifiche su questo problema.

Per prima cosa, otterrò un aumento delle prestazioni leggendo in modo asincrono questi file, se avrò bisogno dell'intera linea, che di solito è breve, ma di lunghezza variabile (non esiste alcuna relazione tra ciascuna delle righe nel file)?

In secondo luogo, come posso convertire il codice sopra, in una lettura asincrona, così posso elaborare ogni riga per riga, come faccio ora?

È stato utile?

Soluzione

Invece di fare in modo che la riga indichi Async, potresti provare a fare in modo che il file indichi Async. Ciò comprende tutto il codice della domanda in un delegato singolo lavoratore.

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

Altri suggerimenti

Il modello asincrono è BeginRead () / EndRead ().

Il fatto che tu abbia o meno una spinta dipende molto da cos'altro sta succedendo nel momento in cui stai facendo le letture. C'è qualcos'altro che la tua app può fare durante l'attesa delle letture? Altrimenti, andare in modalità asincrona non aiuterà molto ...

Le letture asincrone finiranno per far cercare la testa di più per ogni blocco. Otterrai un miglioramento delle prestazioni migliore da una buona deframmentazione dei file sul filesystem e usando la lettura sincrona.

Come già sottolineato, l'invio dell'elaborazione della linea ad altri thread dovrebbe dare una spinta (specialmente su CPU multi-core)

Se le prestazioni sono super critiche, consiglierei di esaminare l'interoper per FILE_FLAG_SEQUENTIAL_SCAN Vedi dettagli qui

Meglio ancora scrivere una piccola app C ++ che scansiona il file con quel flag attivo per vedere se migliora le prestazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top