2010-08-17 16 views
31

Oto moja sytuacja. Chciałbym, aby pisanie do systemu plików było jak najbardziej efektywne w mojej aplikacji. Aplikacja jest wielowątkowa i każdy wątek może pisać do tego samego pliku. Czy istnieje sposób, że mogę zapisać się do pliku asynchronicznie z każdego wątku, nie mając zapisów w różnych wątkach, razem mówiąc, razem?Zapisuj do pliku z wielu wątków asynchronicznie C#

Używam C# i .NET 3.5, i mam również zainstalowane rozszerzenia reaktywne.

Odpowiedz

11

Spójrz na Asynchronous I/O. Spowoduje to zwolnienie procesora, aby kontynuować wykonywanie innych zadań.
Połącz z ReaderWriterLock jak @Jack B Zwinny wspomniano

Jeśli przez

piśmie do systemu plików jako wydajny jak to możliwe

ty li podejmowania rzeczywistego pliku I/O tak szybko jak to możliwe będziesz miał trudności z przyspieszeniem, dysk jest fizycznie wolniejszy. Może dyski SSD?

+2

To nie wydaje się odpowiedzieć na pytanie, zagadnienie "bang bang together". –

+0

Tak, w jaki sposób zapobiega się kolizji napadów asynchronicznych? –

+2

W ten sam sposób radzimy sobie z rywalizacją o zasoby w systemie wielowątkowym. Blokady. ReadWriterLock (lub ReaderWriterLockSlim z 4.0/Parallel Extensions + 3.5) pozwala na równoczesne wielokrotne odczyty, więc jeśli jest to coś, co chcesz, użyj go. –

3

Użyj blokad dostępu do strumienia plików.

7

Co chciałbym zrobić, to mieć osobny wątek roboczy poświęcony na pisanie plików. Kiedy jeden z twoich innych wątków musi zapisać jakieś dane, powinien wywołać funkcję dodania danych do tablicy ArrayList (lub innego kontenera/klasy). Wewnątrz tej funkcji powinna znajdować się instrukcja blokująca u góry, aby zapobiec wykonywaniu jednocześnie więcej niż jednego wątku. Po dodaniu odwołania do tablicy ArrayList jest ona zwracana i kontynuowana z zadaniami. Istnieje kilka sposobów na obsługę napisanych wątków. Prawdopodobnie najprostszy jest po prostu umieszczenie go w nieskończonej pętli z instrukcją sleep na końcu, tak aby nie przeżuła procesora (ów). Innym sposobem jest użycie wątków pierwotnych i przejście do stanu oczekiwania, gdy nie ma już danych do zapisania. Ta metoda oznacza, że ​​musisz aktywować wątek za pomocą metody ManualResetEvent.Set.

Istnieje wiele różnych sposobów odczytywania i zapisywania plików w .NET. Pisałem benchmark program i dać wyniki w moim blogu:

http://designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp

Polecam przy użyciu metod Okienka readfile i WriteFile jeśli trzeba wydajność. Unikaj żadnych metod asynchronicznych, ponieważ wyniki testów porównawczych pokazują, że masz lepszą wydajność dzięki synchronicznym metodom We/Wy.

Bob Bryan MCSD

5

Podczas zamki oparte wątek może rozwiązać ten problem, istnieje sposób, który działa na wątków, ale jest prawdopodobnie najlepiej stosować, gdy masz wiele procesów pisanie do końca pojedynczego pliku.

Aby uzyskać to zachowanie całej procesów (lub nitek też), określić, że chcesz Dołącz atomowy pisze do systemu operacyjnego, gdy uchwyty plików OS są tworzone. Odbywa się to poprzez określenie O_APPEND pod Posix (Linux, Unix) i FILE_APPEND_DATA w systemie Windows.

W języku C# nie zadzwonić lub system OS „open” „” CreateFile zwraca się bezpośrednio, ale istnieją sposoby, aby uzyskać ten wynik.

Zapytałem, jak to zrobić w Windows jakiś czas temu, a jeszcze dwie dobre odpowiedzi tutaj: How can I do an atomic write/append in C#, or how do I get files opened with the FILE_APPEND_DATA flag?

Zasadniczo, można użyć FileStream() lub PInvoke, chciałbym zaproponować FileStream() nad PInvoke z oczywistych względów .

Możesz użyć argumentów konstruktora do FileStream(), aby określić asynchroniczne operacje na plikach i we/wy oprócz flagi FileSystemRights.AppendData, która powinna zapewnić zarówno asynchroniczne operacje wejścia/wyjścia i zapisu atomowego do pliku.

Ostrzeżenie: Niektóre systemy operacyjne mają ograniczenia maksymalnej liczby bajtów, które mogą być zapisane w ten sposób w sposób atomowy, a przekroczenie tego progu spowoduje usunięcie obietnicy atomowej.

Z tego powodu, polecam pozostać przy zarządzaniu rywalizacją stylów lock(), starając się rozwiązać problem w ramach jednego procesu.

3

Dla tych, którzy wolą kod, używam następujące zrobić zdalne rejestrowanie z aplikacji internetowych ...

public static class LoggingExtensions 
{ 
    static ReaderWriterLock locker = new ReaderWriterLock(); 
    public static void WriteDebug(this string text) 
    { 
     try 
     { 
      locker.AcquireWriterLock(int.MaxValue); //You might wanna change timeout value 
      System.IO.File.AppendAllLines(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Replace("file:\\", ""), "debug.txt"), new[] { text }); 
     } 
     finally 
     { 
      locker.ReleaseWriterLock(); 
     } 
    } 
} 

Nadzieja to zaoszczędzić trochę czasu

+0

Bardzo ładne! Brakuje jednej rzeczy z podpisu metody, jeśli próbujesz uczynić tę metodę rozszerzenia Ciągów. Chciałbym poprzedzić "tekst ciągu" z "tym tekstem ciągu" dla pierwszego parametru. –

+0

@JasonFoglia Cześć Jason, gotowe. –

+0

Pytanie określone * asynchronicznie *. To wszystko jest synchroniczne. – Servy

Powiązane problemy