2013-04-24 14 views
6

Muszę napisać tysiące dynamicznie generowanych linii do pliku tekstowego. Mam dwie możliwości, które zużywają mniej zasobów i są szybsze od innych?Co zużywa mniej zasobów i czy jest szybsze przechowywanie File.AppendText lub File.WriteAllText w StringBuilder?

A. Korzystanie StringBuilder i File.WriteAllText

StringBuilder sb = new StringBuilder(); 
foreach(Data dataItem in Datas) 
{ 
sb.AppendLine(String.Format("{0}, {1}-{2}",dataItem .Property1,dataItem .Property2,dataItem .Property3)); 
} 
File.WriteAllText("C:\\example.txt", sb.ToString(), new UTF8Encoding(false)); 

B. Korzystanie File.AppendText

using(StreamWriter sw = File.AppendText("C:\\example.txt")){ 
           foreach (Data dataItem in Datas) 
           { 
            sw.WriteLine(String.Format("{0}, {1}-{2}",dataItem .Property1,dataItem .Property2,dataItem .Property3)); 
           } 
          } 
+5

http://ericlippert.com/2012/12/17/performance-rant/ –

+0

Muszę wykonać tę operację tak szybko, jak to tylko możliwe, ponieważ wiąże się to z tworzeniem sieci i pisaniem baz danych. I mam pewne wąskie gardła, więc zadaję to pytanie, ponieważ potrzebuję, nie dlatego, że nie jestem świadomy artykułu, który łączyłeś. –

+1

Nie jestem pewien, czy prędkość powinna być tutaj głównym problemem. Wykorzystanie pamięci wyraźnie decyduje o Twojej decyzji. Jeśli dane są zawsze małe, wystarczy przeprowadzić kilka testów, aby ustalić, która z nich jest szybsza. – juharr

Odpowiedz

14

Twoja pierwsza wersja, która umieszcza wszystko w pliku StringBuilder, a następnie zapisuje go, pochłonie najwięcej pamięci. Jeśli tekst jest bardzo duży, możesz stracić pamięć. Ma potencjał, by być szybszym, ale może być wolniejszy.

Druga opcja będzie zużywać znacznie mniej pamięci (w zasadzie tylko bufor StreamWriter) i będzie działać bardzo dobrze. Polecam tę opcję. Działa dobrze - prawdopodobnie lepiej niż pierwsza metoda - i nie ma takiego samego potencjału do wyczerpania pamięci.

Możesz go znacznie przyspieszyć, zwiększając rozmiar bufora wyjściowego. Zamiast

File.AppendText("filename") 

Tworzenie strumienia z:

const int BufferSize = 65536; // 64 Kilobytes 
StreamWriter sw = new StreamWriter("filename", true, Encoding.UTF8, BufferSize); 

rozmiar bufora 64K daje znacznie lepszą wydajność niż domyślny rozmiar bufora 4K. Możesz go powiększyć, ale odkryłem, że większy niż 64K daje minimalne przyrosty wydajności, a na niektórych systemach może faktycznie zmniejszyć wydajność .

+0

Ten rozmiar bufora jest trudny do przewidzenia, ponieważ nigdy nie wiadomo, ile linii i danych zajmuje. Myślę, że między 2k a 4k. Miałem ryzyko OutOfMemoryException, jeśli arbitralnie wybiorę mniejszy bufor niż to, czego potrzebuję. –

+0

@ AlbertoLeón: Nie, wybieranie zbyt małego rozmiaru bufora nie spowoduje wyjątku braku pamięci. To tylko tymczasowy bufor, którego używa 'StreamWriter', aby uniemożliwić mu wywoływanie funkcji Windows' Write' dla każdego znaku. Buforuje dane, a następnie zapisuje je w blokach. Nie otrzymasz błędu, jeśli spróbujesz napisać blok większy niż bufor. –

+0

świetnie! Wtedy myślę, że twoje rozwiązanie poprawia moje drugie podejście, podoba mi się. –

7

Macie co najmniej jeden inny wybór, używając File.AppendAllLines()

var data = from item in Datas 
      select string.Format("{0}, {1}-{2}", item.Property1, item.Property2, item.Property3); 

File.AppendAllLines("Filename", data, new UTF8Encoding(false)); 

To teoretycznie zużyje mniej pamięci niż pierwsze podejście, ponieważ tylko jedna linia na raz będzie buforowana w pamięci.

Prawdopodobnie będzie to prawie dokładnie to samo, co drugie podejście. Po prostu pokazuję ci trzecią alternatywę. Jedyną zaletą tego jest to, że możesz karmić go sekwencją Linq, która czasami może być przydatna.

I prędkość/O będzie karzeł jakiekolwiek inne względy, dlatego należy skupić się na minimalizacji zużycia pamięci jako juharr wspomniano wyżej (a także biorąc pod uwagę zagrożenia związane z przedwczesnym optymalizacja, oczywiście!)

Oznacza to, że przy użyciu sekundę podejście, lub ten, który tu umieściłem.

+0

Myślę, że podoba mi się ten jeden najlepszy. Dobra odpowiedź. –

+0

Jestem zaskoczony, ponieważ zmniejszono liczbę linii. Jest bardziej czytelny. Ale czym są dane var? Czy tablica ciągów? –

+0

@ AlbertoLeón: 'data' to' IEnumerable '. Będziesz musiał przeczytać LINQ, aby zrozumieć konsekwencje tego. –

Powiązane problemy