【问题标题】:I need very big array length(size) in C#我在 C# 中需要非常大的数组长度(大小)
【发布时间】:2013-10-24 21:47:37
【问题描述】:
public double[] result = new double[ ??? ];

我正在存储结果,结果总数大于最大 int32 的 2,147,483,647。

我尝试了 biginteger、ulong 等,但它们都给了我错误。

如何扩展可以在其中存储 > 50,147,483,647 个结果(双精度)的数组的大小?

谢谢...

【问题讨论】:

  • 你真的有 373 GB 的内存吗?
  • 听起来您需要不同的数据结构。
  • 绝对是 XY 问题
  • 如果我使用那么多页面文件,是的:)
  • 你真的需要内存中的所有数据吗?为什么不直接将其卸载到数据库中?

标签: c# arrays size biginteger


【解决方案1】:

2,147,483,648 doubles 的数组将占用 16GB 内存。对某些人来说,这没什么大不了的。如果我分配其中一些数组,我的服务器甚至都不会费心点击页面文件。并不意味着这是个好主意。

当您处理这样的大量数据时,您应该尽量减少进程对内存的影响。有几种方法可以解决这个问题,具体取决于您处理数据的方式。


稀疏数组

如果您的数组是稀疏填充的 - 大量默认/空值和一小部分实际有效/有用的数据 - 那么稀疏数组可以大大减少内存需求。您可以编写各种实现来优化不同的分布配置文件:随机分布、分组值、任意连续组等。

适用于任何类型的包含数据,包括复杂的类。有一些开销,因此当填充百分比很高时,实际上可能比裸数组更差。当然,您仍将使用内存来存储实际数据。

简单的平面文件

将数据存储在磁盘上,为文件创建一个读/写FileStream,并将其封装在一个包装器中,让您可以像访问内存数组一样访问文件的内容。最简单的实现将为您从文件中顺序读取提供合理的用途。随机读取和写入可能会减慢您的速度,但您可以在后台进行一些缓冲以帮助缓解速度问题。

这种方法适用于任何具有静态大小的类型,包括可以复制到/从文件中的字节范围复制的结构。不适用于字符串等动态大小的数据。

复杂的平面文件

如果您需要处理动态大小的记录、稀疏数据等,那么您也许可以设计一种可以优雅地处理它的文件格式。再说一次,此时数据库可能是更好的选择。

内存映射文件

与其他文件选项相同,但使用不同的机制来访问数据。有关如何使用 .NET 中的内存映射文件的更多信息,请参阅 System.IO.MemoryMappedFile

数据库存储

根据数据的性质,将其存储在数据库中可能对您有用。然而,对于大量 doubles 来说,这不太可能是一个很好的选择。在数据库中读取/写入数据的开销,加上存储开销 - 每行将至少需要有一个行标识,对于大型记录集可能是 BIG_INT(8 字节整数),加倍数据的大小立即生效。加上索引、行存储等的开销,您可以很容易地增加数据的大小。

数据库非常适合存储和处理复杂的数据。这就是他们的目的。如果您有可变宽度数据(字符串等),那么数据库可能是您最好的选择之一。另一方面,它们通常不是处理大量非常简单的数据的最佳解决方案。


无论您选择哪种方式,您都可以创建一个 IList<T> 兼容的类来封装您的数据。这让您编写的代码不需要知道如何数据是存储的,只需要知道它是什么

【讨论】:

  • 致编辑我的答案的人,因为“SSD 现在很普遍,随机读取速度慢得多不再是问题”,删除您更改的部分并没有改善答案。我的数据中心存储并不完全是 SSD,由于预读优化,顺序读取仍然比随机读取快。如果您有更好的答案,请自行添加。
  • Corey 指出,许多服务器和桌面设备仍然使用硬盘驱动器进行大容量存储,您的程序可能在其上运行或对存储的数据进行操作。除非您愿意规定它们(例如最低规格),否则您不应该对用户的硬件做出假设。
【解决方案2】:

BCL 数组无法做到这一点。
有人写了一个分块的BigArray<T> class 可以。

但是,这不会神奇地创建足够的内存来存储它。

【讨论】:

    【解决方案3】:

    你不能。即使使用gcAllowVeryLargeObjects,数组中任何维度的最大大小(非bytes)也是2,146,435,071

    因此,您需要重新考虑您的设计,或使用替代实现,例如锯齿状数组。

    【讨论】:

    【解决方案4】:

    另一种可能的方法是实现您自己的 BigList。首先注意 List 是作为一个数组实现的。此外,您可以在构造函数中设置 List 的初始大小,因此如果您知道它会很大,请预先获取一大块内存。

    然后

    public class myBigList<T> : List<List<T>>
    {
    
    }
    

    或者,也许更可取的是,使用 has-a 方法:

    public class myBigList<T>
    {
       List<List<T>> theList;
    }
    

    在执行此操作时,您需要重新实现索引器,以便您可以使用除法和模数在后备存储中找到正确的索引。然后您可以使用 BigInt 作为索引。在您的自定义索引器中,您会将 BigInt 分解为两个合法大小的整数。

    【讨论】:

      【解决方案5】:

      我遇到了同样的问题。我使用一个列表来解决它,该列表很好地模仿了一个数组,但可以远远超出 2Gb 的限制。 Ex List 它适用于在 32Gb 计算机上运行的 250k x 250k sbyte,即使这个大象代表 60Gb+ 空间:-)

      【讨论】:

      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      【解决方案6】:

      C# 数组的大小限制为System.Int32.MaxValue

      对于更大的,使用List&lt;T&gt;(其中 T 是你想要持有的任何东西)。

      更多:What is the Maximum Size that an Array can hold?

      【讨论】:

      • 您知道List&lt;T&gt; 由数组支持吗?
      猜你喜欢
      • 2011-02-20
      • 2020-11-11
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      相关资源
      最近更新 更多