我的字典大小正常吗?

时间:2011-11-09 13:13:15

标签: c# .net performance sizeof

我有一个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倍。

这听起来不错吗?

6 个答案:

答案 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>
  • 如果每个字段需要超过1个字符,则可以使用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来实施EqualsGetHashCodeIEquatable<AllCompareElements>IComparable<AllCompareElements>

答案 4 :(得分:1)

如果您的文件是以ANSIUTF-8编码的(但没有特殊字符,则大小与ANSI 相同)(每个字符1个字节)和string - "Represents text as a series of Unicode characters."(Unicode = UTF-16,每个字符4个字节),它是它的4倍。

答案 5 :(得分:0)

通过将文件加载到字典中的操作分配了600M ... 建议它是一个昂贵的操作,它可能有助于衡量任何优化的有效性,但是对于字典占用多少内存,相当无用。

我会按照直接关闭的建议推迟分裂。

在我看来,你已经对速度进行了优化,并且在内存占用空间上花费了大量的成本。