c# - 处理大型数据集和内存限制

标签 c# out-of-memory large-data

<分区>

我正在使用一些代码来比较大量对象并存储所有匹配项。

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

我该如何解决这个问题?

在比较过程中,我应该写入内存,然后让其他东西将结果写入磁盘/rdbms。即创建一个缓冲区。

最佳答案

事实上,它确实取决于您的环境,尤其是取决于您的操作系统 x86 或 x64。在此处查看更多详细信息:Memory in depth

1.您拥有高级方案,其中流媒体是您所需要的。确切的解决方案取决于您从何处提取数据。在从 SQL 数据库中提取数据的情况下,您可以对 SqlDataReader 使用流式处理,在这种情况下它与异步紧密耦合,示例代码:

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
            }
          }
      }
}

此链接将显示更多详细信息:Retrieving large data set .但是,请记住,这种方法会强制您在连接字符串中使用异步以及处理异步代码,这总是会增加复杂性,尤其是当您想要用规范/测试覆盖它时。

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

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

 if (!canRead)
  break;
}

您可以通过估计 1 行数据的大小(基于表架构,msdn article)来粗略计算批处理的大小,或者只是使其可配置并使用最合适的值。这种方法的主要优点是您需要对代码进行最少的更改,并且代码本身保持同步。缺点是您必须保持事件连接或每次都打开一个新连接,而是维护您已经读取的记录和仍然需要获取的记录。

最后,这两个选项都会迫使你考虑一些更高级的问题,比如如果只获取了一部分数据,然后连接丢失你应该怎么做(需要一些故障转移机制),取消的能力一定超时后长时间运行的检索操作等。

总而言之,如果您不想处理大数据带来的额外复杂性,请将此任务委派给市场上可用的任何东西,即数据库或第 3 方框架。如果你觉得你的团队有足够的技能来做这件事,那就继续自己实现吧——将比较结果保存在磁盘文件中,利用内存缓存或者只是将该数据推送到数据库中

关于c# - 处理大型数据集和内存限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24293105/

相关文章:

c# - 检测数据库查询更新

c# - 在 C# 中使用 ExpressionVisitor 识别 lambda 表达式中的括号

c# - 是否可以判断一个对象在运行时是否可等待?

安卓。如何使用自定义 ArrayAdapter 和 ViewPagers 节省内存

java - Java 中 XML JDOM 解析器中的 OutOfMemoryError

vba - 如何在每半小时后获得最近的日期

c# - 在没有 Visual Studio 的机器上从 IIS 运行 ASP.Net 网页

java8 "java.lang.OutOfMemoryError: Metaspace"

arrays - 在 Swift 中存储/访问大量数据

mysql - 随机化大型 MySQL 表中的时间戳列