我有一个150mb的文件。每一行都由相同的格式组成,例如/
I,h,q,q,3,A,5,Q,3,[,5,Q,8,c,3,N,3,E,4,F,4,g,4,I,V,9000,0000001-100,G9999999990001800000000000001,G9999999990000001100PDNELKKMMCNELRQNWJ010, , , , , , ,D,Z,
我有Dictionary<string, List<string>>
通过打开文件,读取每一行,从行中获取元素并将其添加到字典中来填充它,然后关闭文件。
StreamReader s = File.OpenText(file);
string lineData = null;
while ((lineData = s.ReadLine()) != null)
{
var elements = lineData.Split(',');
var compareElements = elements.Take(24);
FileData.Add(elements[27], new List<string>(compareElements));
}
s.Close();
使用此answer中的方法,我计算出的词典为600mb。那是文件的4倍。
这听起来不错吗?
答案 0 :(得分:3)
除了方法不是很可靠之外,在你的情况下还有更大的开销。您是否注意到循环的每次迭代都会创建elements
数组的新实例,lineData
字符串,而elements.Take
也会在每次调用时创建一些内部变量?由于你可能有足够的内存,.NET垃圾收集器并不打算收集它们,所以当你在循环之前和之后测量TotalMemory时,你也测量所有这些变量,不仅是你的字典,尽管它可能是唯一的之后仍然在范围内。
答案 1 :(得分:1)
是的,因为你正在将字符转换为字符串指针,每个字符串指针为4或8个字节。
答案 2 :(得分:1)
我假设您的文件是UTF-8编码,主要包含ASCII。 C#中的字符串是UTF-16,所以这就解释了大部分的大小差异(因子为2)。当然,数据结构也有一些开销。
答案 3 :(得分:1)
这些实体中的大多数只占用一个字符,但您将它们存储为字符串。那些字符串单独的引用指针将使至少两倍的空间(在UTF8的情况下可能是4-8倍)。然后是为字典保留哈希表的开销。
List<>
本身应该是非常有效的存储(它在内部使用数组)
改进空间:
List<char>
或char[]
代替List<string>
struct Field { char a,b/*,...*/; }
和List而不是List 您可以放弃急切的字段提取 [&lt; - recommended]:
var dict = File.ReadAllLines(file)
.ToDictionary(line => line.Split(',')[27]);
这使您有机会按需访问compareElements:
string[] compareElements = dicts["key27"].Split(',')/*.Take(24).ToArray()*/;
这是运行时/存储成本权衡的典型例子
编辑一个明显的混合体将是:
struct AllCompareElements
{
public char field1, field2, ... field24;
// perhaps:
public char[2] field13; // for the exceptional field that is longer than 1 character
}
高兴地使用Resharper来实施Equals
,GetHashCode
,IEquatable<AllCompareElements>
,IComparable<AllCompareElements>
答案 4 :(得分:1)
如果您的文件是以ANSI
或UTF-8
编码的(但没有特殊字符,则大小与ANSI
相同)(每个字符1个字节)和string - "Represents text as a series of Unicode characters."(Unicode = UTF-16,每个字符4个字节),它是它的4倍。
答案 5 :(得分:0)
通过将文件加载到字典中的操作分配了600M ... 建议它是一个昂贵的操作,它可能有助于衡量任何优化的有效性,但是对于字典占用多少内存,相当无用。
我会按照直接关闭的建议推迟分裂。
在我看来,你已经对速度进行了优化,并且在内存占用空间上花费了大量的成本。