2013-02-11 15 views
9

Właśnie zaczynam od nowych funkcji C# async C#. Czytałem dużo porad na temat równoległych pobrań itp., Ale nic na temat czytania/przetwarzania pliku tekstowego.Używanie asynchronizmu C# 5.0 do odczytu pliku

Miałem stary skrypt, którego używam do filtrowania pliku dziennika i doszedłem do wniosku, że muszę go zaktualizować. Jednak nie jestem pewien, czy moje użycie nowej składni async/await jest poprawne.

W mojej głowie widzę czytanie linii pliku po wierszu i przekazywanie jej do przetworzenia w innym wątku, aby można było kontynuować bez czekania na wynik.

Czy dobrze o tym myślę, czy w jaki sposób najlepiej to wdrożyć?

static async Task<string[]> FilterLogFile(string fileLocation) 
{ 
    string line; 

    List<string> matches = new List<string>(); 

    using(TextReader file = File.OpenText(fileLocation)) 
    {   
     while((line = await file.ReadLineAsync()) != null) 
     { 
      CheckForMatch(line, matches); 
     } 
    } 

    return matches.ToArray(); 
} 

Pełen skrypt: http://share.linqpad.net/29kgbe.linq

+0

Wystarczyło spojrzeć na [msdn docs] (http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx), co jasno pokazało, że myślę o słowach kluczowych w złym droga. Nie sądzę, by można było wiele zrobić, aby poprawić wydajność w tym przypadku. –

+1

Czy mogę to polecić? http://blog.jerrynixon.com/2012/06/windows-8-how-to-read-files-in-winrt.html –

Odpowiedz

9

W mojej głowie widzę to czytanie pliku linia po linii i przekazania go do przetworzenia w innym wątku, dzięki czemu można kontynuować bez oczekiwania na wynik.

Ale to nie jest to, co robi twój kod. Zamiast tego (asynchronicznie) zwrócisz tablicę po zakończeniu odczytu. Jeśli chcesz asynchronicznie zwracać dopasowania jeden po drugim, potrzebujesz jakiejś asynchronicznej kolekcji. Do tego można użyć bloku z TPL Dataflow. Na przykład:

ISourceBlock<string> FilterLogFile(string fileLocation) 
{ 
    var block = new BufferBlock<string>(); 

    Task.Run(async() => 
    { 
     string line; 

     using(TextReader file = File.OpenText(fileLocation)) 
     {   
      while((line = await file.ReadLineAsync()) != null) 
      { 
       var match = GetMatch(line); 

       if (match != null) 
        block.Post(match); 
      } 
     } 

     block.Complete(); 
    }); 

    return block; 
} 

(Trzeba by dodać obsługę błędów, prawdopodobnie przez faulting wracającą blok.)

Można by następnie połączyć wracającą bloku do innego bloku, który będzie przetwarzać wyniki. Lub możesz przeczytać je bezpośrednio z bloku (używając ReceiveAsync()).


Ale patrząc na pełny kod, nie jestem pewien, że to podejście byłoby, że przydatna. Ze względu na sposób, w jaki przetwarzasz wyniki (grupowanie, a następnie porządkowanie według liczby w każdej grupie), nie możesz z nimi wiele zrobić, dopóki nie uzyskasz ich wszystkich.

+0

To ma więcej sensu. Dziękujemy za przykładowy kod przepływu danych tpl. Czy powinienem wtedy oczekiwać na listę meczów lub metodę "CheckForMatch"? Jak to sobie wyobrażam, nie różni się zbytnio od biegania synchronicznego. –

+1

@Sam Powinieneś używać 'await' tylko tam, gdzie ma to sens, głównie w kodzie, który używa IO. Różnice tutaj od kodu synchronicznego: 1. 'await file.ReadFileAsync()' nie blokuje wątku, więc jest bardziej wydajny. 2. Możesz przetwarzać wyniki po ich przeczytaniu, bez blokowania innego wątku. – svick

Powiązane problemy