如何在C#中处理大量数据?

时间:2015-07-14 11:58:35

标签: c# parsing memory-management data-structures

我将数据存储在几个单独的文本文件中,然后我会解析和分析。

处理的数据大小差异很大。它的范围从几百兆字节(或更少)到10千兆字节。

我开始将解析后的数据存储在List<DataItem>中,因为我想在分析过程中执行BinarySearch()。但是,如果解析了太多数据,程序将抛出OutOfMemory-Exception。解析器可以处理的确切数量取决于内存的碎片。有时它只有1.5 GB的文件,有些时候它只有3 GB。

目前我使用的List<List<DataItem>>条目数量有限,因为我认为它会改变任何东西。但是没有任何重大改进。

我尝试的另一种方法是序列化解析器数据,然后根据需要对其进行反序列化。这种方法的结果更糟。整个过程耗时更长。

我查看了内存映射文件,但我真的不知道它们是否可以帮助我,因为我之前从未使用它们。他们会吗?

那么如何快速访问所有文件中的数据,而不会有OutOfMemoryException并根据其属性查找DataItem的危险?

编辑:解析器大致如下:

void Parse() {
   LoadFile();
   for (int currentLine = 1; currentLine < MAX_NUMBER_OF_LINES; ++currentLine) {
      string line = GetLineOfFile(currentLine);
      string[] tokens = SplitLineIntoTokens(line);
      DataItem data = PutTokensIntoDataItem(tokens);
      try {
         List<DataItem>.Add(data);
      } catch (OutOfMemoryException ex) {}
   }
}

void LoadFile(){
 DirectoryInfo di = new DirectroyInfo(Path); 
 FileInfo[] fileList = di.GetFiles(); 
 foreach(FileInfo fi in fileList) 
 { 
  //... 
  StreamReader file = new SreamReader(fi.FullName); 
  //... 
  while(!file.EndOfStram) 
   strHelp = file.ReadLine(); 
  //...
 }
}

2 个答案:

答案 0 :(得分:1)

如果您问题中的代码代表实际代码,则看起来您正在将所有文件中的所有数据读入内存,然后进行解析。也就是说,你有:

Parse()
    LoadFile();
    for each line
        ....

您的LoadFile将所有文件加载到内存中。或者看起来如此。这非常浪费,因为除了解析时创建的对象外,还保留了所有未解析行的列表。

您可以改为一次只加载一行,解析它,然后丢弃未解析的行。例如:

void Parse()
{
    foreach (var line in GetFileLines())
    {
    }
}

IEnumerable<string> GetFileLines()
{
    foreach (var fileName in Directory.EnumerateFiles(Path))
    {
        foreach (var line in File.ReadLines(fileName)
        {
            yield return line;
        }
    }
}

这限制了用于保存文件名的内存量,更重要的是,限制了未解析行占用的内存量。

此外,如果您对最终数据中的行数有上限,则可以预先分配列表,以便添加到列表中不会导致重新分配。因此,如果您知道您的文件将包含不超过1亿行,您可以写:

void Parse()
{
    var dataItems = new List<DataItem>(100000000);
    foreach (var line in GetFileLines())
    {
        data = tokenize_and_build(line);
        dataItems.Add(data);
    }
}

这可以减少碎片和内存不足错误,因为列表已预先分配以保存您期望的最大行数。如果预分配有效,那么您就知道自己有足够的内存来保存对正在构建的数据项的引用。

如果内存不足,则必须查看数据项的结构。也许您在其中存储了太多信息,或者有办法减少用于存储这些项目的内存量。但是,如果您需要帮助减少其占用空间,则需要向我们提供有关数据结构的更多信息。

答案 1 :(得分:0)

您可以使用:

我认为它会减少内存异常并使文件处理更快。