使用大型数据集和内存限制

jim*_*jim 1 c# out-of-memory large-data

我正在使用一些代码来比较大型对象集合并存储所有匹配项.

不出所料,我刚刚遇到了一个 System.OutofMemoryException

我怎样才能解决这个问题?

在比较期间,我应该写入内存,然后将其他内容写入磁盘/ rdbms.即创建一个缓冲区.

Bor*_*lov 6

实际上,它确实取决于您的环境,尤其是您的操作系统x86或x64.在这里查看更多细节:深度记忆

1.你有先进的场景,你需要流媒体.确切的解决方案取决于您从哪里提取数据.如果从SQL数据库中提取数据,您可以使用流式传输SqlDataReader,在这种情况下,它与async紧密耦合,示例代码:

using (SqlDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
{
     if (await reader.ReadAsync())
     {
         if (!(await reader.IsDBNullAsync(0)))
         {
            using (var dataStream = reader.GetStream(0))
            {
                //process the data
            }
          }
      }
}
Run Code Online (Sandbox Code Playgroud)

此链接将显示更多详细信息:检索大型数据集.但是,请记住,这种方法会强制您在连接字符串中使用异步以及处理异步代码,这总是额外的复杂性,尤其是当您想要使用specs/tests进行覆盖时.

2.但是另一种方法是批量处理,即将数据缓冲到某个可接受的限制,然后公开批处理以消耗代码,之后继续获取新的数据批量,除非所有内容都被加载,示例代码:

while(true)
{
 int count = 0;
 bool canRead = reader.Read();
 while(canRead)
 {
  canRead = reader.Read();
  count++;
  if (count >= batchSize)
   break;
 }

 if (!canRead)
  break;
}
Run Code Online (Sandbox Code Playgroud)

您可以通过估计1行数据的大小(基于表模式,msdn文章)粗略计算批处理的大小,或者只是使其可配置并使用最合适的值.这种方法的主要优点是您需要对代码进行微小的更改,并且代码本身保持同步.缺点是您必须每次都保持活动连接或打开新连接,而是维护您已经读取的记录以及仍需要提取的记录.

最后,这两个选项都会强制您处理一些更高级的问题,例如,如果只提取了一部分数据,您应该怎么做?之后连接丢失(需要一些故障转移机制),取消长时间运行的能力在某些超时后检索操作等

总而言之,如果您不想处理大数据引入的额外复杂性,请将此任务委派给市场上可用的任何内容,即数据库或第三方框架.如果您认为您的团队有足够的技能,那么请继续并自己实施 - 在磁盘文件中保留比较结果,利用内存缓存或将数据推送到数据库