gpt4 book ai didi

C# 字典和高效内存使用

转载 作者:太空狗 更新时间:2023-10-29 17:45:32 25 4
gpt4 key购买 nike

我有一个工具可以比较 2 个 csv 文件,然后将每个单元格放入 6 个桶中的一个。基本上,它读取 csv 文件(使用快速 csv 阅读器,来源:http://www.codeproject.com/KB/database/CsvReader.aspx),然后根据用户提供的键创建与每个文件相关的字典。然后我遍历字典比较值并写入结果 csv 文件。

虽然它非常快,但在内存使用方面效率非常低。我无法将盒子上超过 150 MB 的文件与 3 GB 物理内存进行比较。

这是读取预期文件的代码片段。在这篇文章的最后,任务管理器的内存使用量接近 500 MB。

// 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");
}

我可以做些什么来提高内存效率吗?我可以在上面做些什么来减少内存消耗?

欢迎提出任何想法。

感谢大家的反馈。

我已经按照建议合并了更改,以将行的索引而不是行本身存储在字典中。

这是新实现的相同代码片段。

// 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();

但是,问题是我需要内存中的两个数据集。实际上,我遍历了两个字典,根据键查找匹配项、不匹配项、重复项和丢失项。

使用这种存储行索引的方法,我仍然使用大量内存,因为对于动态访问,我现在必须使用 csv 读取器的缓存版本。因此,虽然字典现在小得多,但数据缓存弥补了节省,我最终还是得到了大致相似的内存使用量。

希望,我是有道理的...:)

一种选择是完全摆脱字典,只循环遍历 2 个文件,但不确定性能是否与比较 2 个字典一样快。

非常感谢任何意见。

最佳答案

您可以将 keyExp 替换为 StringBuilder。在这样的循环中重新分配字符串将继续分配更多内存,因为字符串是不可变的。

StringBuilder keyExp = new StringBuilder();
...
keyExp.Append("|" + readerCSVExp[i - 1]) ;
...

很多字符串都是一样的吗?你可以试试 interning them , 然后任何相同的字符串将共享相同的内存而不是副本...

rowExp[fieldCount] = String.Intern(rowNumExp.ToString()); 

// Dedup Expected
string internedKey = (String.Intern(keyExp.ToString()));
if (!(dictExp.ContainsKey(internedKey)))
{
dictExp.Add(internedKey, rowExp);
}
else
{
listDupExp.Add(rowExp);
}

我不确定代码是如何工作的,但是...除此之外我会说你不需要在字典中保留 rowExp,保留其他东西,比如数字和在另一个文件中将 rowExp 写回磁盘。这可能会为您节省最多的内存,因为这似乎是文件中的字符串数组,所以可能很大。如果您将它写入文件并将数字保存在文件中,那么您可以在以后需要处理时再次返回它。如果您将文件中的偏移量保存为字典中的值,您将能够快速再次找到它。也许 :)。

关于C# 字典和高效内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2164845/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com