Mam narzędzie do porównywania 2 plików CSV, a następnie do każdej z 6 komórek. Zasadniczo, czyta się w plikach csv (używając szybkiego czytnika csv, kredyt: http://www.codeproject.com/KB/database/CsvReader.aspx), a następnie tworzy słownik dotyczący każdego pliku na podstawie kluczy dostarczonych przez użytkownika. Następnie przechodzę przez słowniki porównujące wartości i zapisuję wynikowy plik csv.Słownik C# i efektywne wykorzystanie pamięci
Podczas gdy płonie szybko, jest bardzo nieefektywny pod względem zużycia pamięci. Nie mogę porównać więcej niż 150 MB plików na moim pudełku z pamięcią fizyczną 3 GB.
Oto fragment kodu do odczytania oczekiwanego pliku. Na końcu tego fragmentu zużycie pamięci jest bliskie 500 MB od menedżera zadań.
// Read Expected
long rowNumExp;
System.IO.StreamReader readerStreamExp = new System.IO.StreamReader(@expFile);
SortedDictionary<string, string[]> dictExp = new SortedDictionary<string, string[]>();
List<string[]> listDupExp = new List<string[]>();
using (CsvReader readerCSVExp = new CsvReader(readerStreamExp, hasHeaders, 4096))
{
readerCSVExp.SkipEmptyLines = false;
readerCSVExp.DefaultParseErrorAction = ParseErrorAction.ThrowException;
readerCSVExp.MissingFieldAction = MissingFieldAction.ParseError;
fieldCountExp = readerCSVExp.FieldCount;
string keyExp;
string[] rowExp = null;
while (readerCSVExp.ReadNextRecord())
{
if (hasHeaders == true)
{
rowNumExp = readerCSVExp.CurrentRecordIndex + 2;
}
else
{
rowNumExp = readerCSVExp.CurrentRecordIndex + 1;
}
try
{
rowExp = new string[fieldCount + 1];
}
catch (Exception exExpOutOfMemory)
{
MessageBox.Show(exExpOutOfMemory.Message);
Environment.Exit(1);
}
keyExp = readerCSVExp[keyColumns[0] - 1];
for (int i = 1; i < keyColumns.Length; i++)
{
keyExp = keyExp + "|" + readerCSVExp[i - 1];
}
try
{
readerCSVExp.CopyCurrentRecordTo(rowExp);
}
catch (Exception exExpCSVOutOfMemory)
{
MessageBox.Show(exExpCSVOutOfMemory.Message);
Environment.Exit(1);
}
try
{
rowExp[fieldCount] = rowNumExp.ToString();
}
catch (Exception exExpRowNumOutOfMemory)
{
MessageBox.Show(exExpRowNumOutOfMemory.Message);
Environment.Exit(1);
}
// Dedup Expected
if (!(dictExp.ContainsKey(keyExp)))
{
dictExp.Add(keyExp, rowExp);
}
else
{
listDupExp.Add(rowExp);
}
}
logFile.WriteLine("Done Reading Expected File at " + DateTime.Now);
Console.WriteLine("Done Reading Expected File at " + DateTime.Now + "\r\n");
logFile.WriteLine("Done Creating Expected Dictionary at " + DateTime.Now);
logFile.WriteLine("Done Identifying Expected Duplicates at " + DateTime.Now + "\r\n");
}
Czy jest coś, co mogę zrobić, aby zwiększyć wydajność pamięci? Coś, co mogłem zrobić inaczej, aby konsumować mniej mermory?
Wszelkie pomysły są mile widziane.
Dzięki chłopaki za wszystkie opinie.
Wprowadziłem zmiany zgodnie z sugestią, aby zapisać indeks wiersza zamiast samego wiersza w słownikach.
Oto ten sam fragment kodu z nową implementacją.
// Read Expected
long rowNumExp;
SortedDictionary<string, long> dictExp = new SortedDictionary<string, long>();
System.Text.StringBuilder keyExp = new System.Text.StringBuilder();
while (readerCSVExp.ReadNextRecord())
{
if (hasHeaders == true)
{
rowNumExp = readerCSVExp.CurrentRecordIndex + 2;
}
else
{
rowNumExp = readerCSVExp.CurrentRecordIndex + 1;
}
for (int i = 0; i < keyColumns.Length - 1; i++)
{
keyExp.Append(readerCSVExp[keyColumns[i] - 1]);
keyExp.Append("|");
}
keyExp.Append(readerCSVExp[keyColumns[keyColumns.Length - 1] - 1]);
// Dedup Expected
if (!(dictExp.ContainsKey(keyExp.ToString())))
{
dictExp.Add(keyExp.ToString(), rowNumExp);
}
else
{
// Process Expected Duplicates
string dupExp;
for (int i = 0; i < fieldCount; i++)
{
if (i >= fieldCountExp)
{
dupExp = null;
}
else
{
dupExp = readerCSVExp[i];
}
foreach (int keyColumn in keyColumns)
{
if (i == keyColumn - 1)
{
resultCell = "duplicateEXP: '" + dupExp + "'";
resultCell = CreateCSVField(resultCell);
resultsFile.Write(resultCell);
comSumCol = comSumCol + 1;
countDuplicateExp = countDuplicateExp + 1;
}
else
{
if (checkPTColumns(i + 1, passthroughColumns) == false)
{
resultCell = "'" + dupExp + "'";
resultCell = CreateCSVField(resultCell);
resultsFile.Write(resultCell);
countDuplicateExp = countDuplicateExp + 1;
}
else
{
resultCell = "PASSTHROUGH duplicateEXP: '" + dupExp + "'";
resultCell = CreateCSVField(resultCell);
resultsFile.Write(resultCell);
}
comSumCol = comSumCol + 1;
}
}
if (comSumCol <= fieldCount)
{
resultsFile.Write(csComma);
}
}
if (comSumCol == fieldCount + 1)
{
resultsFile.Write(csComma + rowNumExp);
comSumCol = comSumCol + 1;
}
if (comSumCol == fieldCount + 2)
{
resultsFile.Write(csComma);
comSumCol = comSumCol + 1;
}
if (comSumCol > fieldCount + 2)
{
comSumRow = comSumRow + 1;
resultsFile.Write(csCrLf);
comSumCol = 1;
}
}
keyExp.Clear();
}
logFile.WriteLine("Done Reading Expected File at " + DateTime.Now + "\r\n");
Console.WriteLine("Done Reading Expected File at " + DateTime.Now + "\r\n");
logFile.WriteLine("Done Analyzing Expected Duplicates at " + DateTime.Now + "\r\n");
Console.WriteLine("Done Analyzing Expected Duplicates at " + DateTime.Now + "\r\n");
logFile.Flush();
Jednak problem polega na tym, że potrzebuję obu zestawów danych w pamięci. Rzeczywiście, przeglądam zarówno słowniki, które szukają dopasowań, niedopasowań, duplikatów i rezygnacji w oparciu o klucz.
Stosując to podejście do przechowywania indeksu wiersza, nadal używam dużej ilości pamięci, ponieważ do uzyskania dostępu dynamicznego muszę teraz używać buforowanej wersji czytnika csv. Więc chociaż słownik jest teraz znacznie mniejszy, buforowanie danych nadrabia oszczędności, a ja wciąż miałem do czynienia z podobnym wykorzystaniem pamięci.
Hope, mam sensu ... :)
Jedną z opcji jest, aby pozbyć się całkowicie i po prostu słowniku pętla przez 2 pliki, ale nie jestem pewien, czy wydajność byłaby tak szybko jak porównywanie 2 słowniki.
Wszelkie dane wejściowe są mile widziane.
zamiast buforować czytnik csv, nie możesz buforować lokalizacji rekordów w pliku, aby móc później odzyskać te rekordy? kiedy przeglądasz słowniki szukające upuszczenia itp. kluczem jest przeglądanie rzeczywistych danych lub tylko kluczy? –
czy próbowałeś przetłumaczyć ciąg znaków przed przejściem do słownika? czy to miało jakiś wpływ? Czy to wszystko pomogło z wykorzystaniem pamięci? –