Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 与“合作”;“非常非常”;大型阵列_C#_.net_.net 4.5 - Fatal编程技术网

C# 与“合作”;“非常非常”;大型阵列

C# 与“合作”;“非常非常”;大型阵列,c#,.net,.net-4.5,C#,.net,.net 4.5,我需要处理非常大的小型数组(int或float数组),我只针对具有大量ram的机器上的X64,在我的场景中,物理内存从来都不是问题。在查看gcAllowVeryLargeObjects的文档时,我注意到这一点: •对于字节数组和单字节结构数组,任何单个维度的最大索引为2147483591(0x7FFFFFC7),对于其他类型的数组,最大索引为2146435071(0X7FEFFFFF) 现在我的问题是,我实际上“需要”使用比这更大的阵列,这里合适的解决方法是什么?创建数组或其他抽象的数组 知道我

我需要处理非常大的小型数组(int或float数组),我只针对具有大量ram的机器上的X64,在我的场景中,物理内存从来都不是问题。在查看gcAllowVeryLargeObjects的文档时,我注意到这一点:

•对于字节数组和单字节结构数组,任何单个维度的最大索引为2147483591(0x7FFFFFC7),对于其他类型的数组,最大索引为2146435071(0X7FEFFFFF)

现在我的问题是,我实际上“需要”使用比这更大的阵列,这里合适的解决方法是什么?创建数组或其他抽象的数组

知道我主要需要依次访问这些数组(从不随机读取,但通常不同的段会被不同的线程依次读取,可能一次读取100多个线程)我的最佳选择是什么


我可能需要容纳多达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