C# 与“合作”;“非常非常”;大型阵列
我需要处理非常大的小型数组(int或float数组),我只针对具有大量ram的机器上的X64,在我的场景中,物理内存从来都不是问题。在查看gcAllowVeryLargeObjects的文档时,我注意到这一点: •对于字节数组和单字节结构数组,任何单个维度的最大索引为2147483591(0x7FFFFFC7),对于其他类型的数组,最大索引为2146435071(0X7FEFFFFF) 现在我的问题是,我实际上“需要”使用比这更大的阵列,这里合适的解决方法是什么?创建数组或其他抽象的数组 知道我主要需要依次访问这些数组(从不随机读取,但通常不同的段会被不同的线程依次读取,可能一次读取100多个线程)我的最佳选择是什么C# 与“合作”;“非常非常”;大型阵列,c#,.net,.net-4.5,C#,.net,.net 4.5,我需要处理非常大的小型数组(int或float数组),我只针对具有大量ram的机器上的X64,在我的场景中,物理内存从来都不是问题。在查看gcAllowVeryLargeObjects的文档时,我注意到这一点: •对于字节数组和单字节结构数组,任何单个维度的最大索引为2147483591(0x7FFFFFC7),对于其他类型的数组,最大索引为2146435071(0X7FEFFFFF) 现在我的问题是,我实际上“需要”使用比这更大的阵列,这里合适的解决方法是什么?创建数组或其他抽象的数组 知道我
我可能需要容纳多达65 536 000 000个或更多元素的数组。您可以避免使用真实数组,而是通过流模拟它们 如果您希望它是可查找的(确实如此),则限制为长(2^64/2(有符号)位) 然后,您只需索引*n个字节,然后读取n个字节
如果您使用int32或double(n=4),则有2,8e+17个位置的空间。这听起来像是分布式计算的问题,类似于Google Map Reduce
当它对于您当前的基础设施来说太大时,请将其扩展到更多的盒子。我很确定您不可能拥有650000000大小的阵列,因为通常它比计算机内存大(没有操作系统会给软件那么多内存。)可能还有另一个原因。 若出于某种原因,您认为可以获得那个么多的ram,但您认为数组太小,那个么可以尝试使用基于链表的对象(比如堆栈,甚至链表本身)。
链表不受索引数量的限制(如果它在ram范围内)我写这篇文章是为了解决这个问题,但希望有人能提供更好的答案,我可以将其标记为可接受的答案 由于限制是在数组的一个维度上,因此解决方案是使用多维数组,并通过计算位置简单地在多维数组中建立索引,就像它是一个一维数组一样
//pseudocode
var index = some large number;
var index1 = index/sizeofarrays;
var index2 = index%sizeofarrays;
var data = myverylargemultidimentionalarray[index1,index2];
我的建议是使用本机代码(即C++ X64),因为C是不好的循环这么多的元素。在尝试将如此大量的数据加载到RAM之前,请仔细考虑需要从该数据中提取哪些信息。听起来您应该使用流。内存流应该是好的,只要您在读了块之后处理它们 我的猜测是,填充数组的内容的运行速度比消耗它的内容的运行速度快得多?如果是这种情况,您可以将流简单地用作缓冲区。当缓冲区达到临界质量时,在清除后台日志的同时阻止新条目。听起来你已经有足够的内存了,不会有问题 您的缓冲区内容可以分块传递给并行库,并维护一个索引以提供当前索引 伪代码是:
- 接收新项目并添加到超大内存流(内存将复制到此处的页面文件,因此,如果您也有大量磁盘,RAM问题就更少了!)
- 而缓冲区中有项目
- 从缓冲区读取对象
- 进程对象
如果您想在每个任务中利用并行处理,请首先流式处理一个对象块,并将它们作为一个集合与起始索引一起传递给您的方法,这样您仍然可以推断当前项索引。如果您确实必须打破数组长度限制,则必须将数组拆分为大小合适的块。您可以将这些块包装在一个具有适当语义的容器中,就像James McCaffrey不久前在博客中所写的对象一样。还有很多其他类似的 基本思想是使用锯齿状数组来分配要使用的空间。请注意,多维数组不会给您带来任何好处,因为它仍然是单个对象,而锯齿数组是更小的数组数组,每个数组在内存中都是自己的对象(可能不是连续的) 下面是一个非常简单(但不是特别最优)的实现:
public class HugeArray<T> : IEnumerable<T>
where T : struct
{
public static int arysize = (Int32.MaxValue >> 4) / Marshal.SizeOf<T>();
public readonly long Capacity;
private readonly T[][] content;
public T this[long index]
{
get
{
if (index < 0 || index >= Capacity)
throw new IndexOutOfRangeException();
int chunk = (int)(index / arysize);
int offset = (int)(index % arysize);
return content[chunk][offset];
}
set
{
if (index < 0 || index >= Capacity)
throw new IndexOutOfRangeException();
int chunk = (int)(index / arysize);
int offset = (int)(index % arysize);
content[chunk][offset] = value;
}
}
public HugeArray(long capacity)
{
Capacity = capacity;
int nChunks = (int)(capacity / arysize);
int nRemainder = (int)(capacity % arysize);
if (nRemainder == 0)
content = new T[nChunks][];
else
content = new T[nChunks + 1][];
for (int i = 0; i < nChunks; i++)
content[i] = new T[arysize];
if (nRemainder > 0)
content[content.Length - 1] = new T[nRemainder];
}
public IEnumerator<T> GetEnumerator()
{
return content.SelectMany(c => c).GetEnumerator();
}
IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
公共类HugarRay:IEnumerable
其中T:struct
{
公共静态int-arysize=(Int32.MaxValue>>4)/Marshal.SizeOf();
公共只读长容量;
私有只读T[][]内容;
这是什么[长索引]
{
得到
{
如果(索引<0 | |索引>=容量)
抛出新的IndexOutOfRangeException();
int chunk=(int)(索引/大小);
int偏移量=(int)(索引%1大小);
返回内容[块][偏移量];
}
设置
{
如果(索引<0 | |索引>=容量)
抛出新的IndexOutOfRangeException();
int chunk=(int)(索引/大小);
int偏移量=(int)(索引%1大小);
内容[块][偏移]=值;
}
}
公共休格雷(长容量)
{
容量=容量;
int nChunks=(int)(容量/尺寸);
int nRemainder=(int)(容量%1大小);
如果(nMainder==0)
内容=新的T[nChunks][];
其他的
内容=新的T[nChunks+1][];
对于(int i=0;i0)
content[content.Length-1]=新的T[nMainder];
}
公共IEnumerator GetEnumerator()
{
返回content.SelectMany(c=>c).GetEnumerator();
}
IEnumerator System.Collections.IEnumerable.GetEnumerator(){return GetEnumerator();}
}
这一个是静态分配的,但要使其增长以满足需求并不难。J