Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.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
在Go中处理大数据量时使用切片而不是列表_Go_Linked List_Slice - Fatal编程技术网

在Go中处理大数据量时使用切片而不是列表

在Go中处理大数据量时使用切片而不是列表,go,linked-list,slice,Go,Linked List,Slice,我有一个关于Go中切片的实用性的问题。我刚才看到了,但有一个问题我没有看到答案 在我的申请中: 我阅读了一个CSV文件,其中包含大约1000万条记录,每条记录有23列。 对于每条记录,我创建一个结构并将其放入一个链表中。 一旦读取了所有记录,其余的应用程序逻辑将与此链表一起工作。处理逻辑本身与此问题无关。 我之所以喜欢列表而不是片,是因为一个数组/片需要大量的连续内存。另外,由于我事先不知道文件中记录的确切数量的大小,因此我无法预先指定数组大小,我知道Go可以根据需要动态地重新调整切片/数组的尺

我有一个关于Go中切片的实用性的问题。我刚才看到了,但有一个问题我没有看到答案

在我的申请中:

我阅读了一个CSV文件,其中包含大约1000万条记录,每条记录有23列。 对于每条记录,我创建一个结构并将其放入一个链表中。 一旦读取了所有记录,其余的应用程序逻辑将与此链表一起工作。处理逻辑本身与此问题无关。 我之所以喜欢列表而不是片,是因为一个数组/片需要大量的连续内存。另外,由于我事先不知道文件中记录的确切数量的大小,因此我无法预先指定数组大小,我知道Go可以根据需要动态地重新调整切片/数组的尺寸,但对于如此大的数据集来说,这似乎效率极低

我读到的每一篇围棋教程或文章似乎都建议我应该使用切片而不是列表,因为切片可以做列表所能做的一切,但不知何故做得更好。然而,我不明白一个切片如何或为什么对我需要的东西更有帮助?有人有什么想法吗

。。。大约1000万条记录,每条记录有23列。。。我之所以喜欢列表而不是片,是因为一个数组/片需要大量的连续内存

这种连续内存有其自身的优点,也有其自身的缺点。让我们考虑这两个部分。

注意,也可以使用混合方法:一组块。不过,这在这里似乎不太值得

另外,由于我事先不知道文件中记录的确切数量的大小,因此我无法预先指定数组大小,我知道Go可以根据需要动态地重新调整切片/数组的尺寸,但对于如此大的数据集来说,这似乎效率极低

很明显,如果有n条记录,并且您使用列表分配并填写每一条记录一次,则此选项处于启用状态

如果使用一个切片,并且每次都分配一个额外的切片条目,则从“无”开始,将其增大到大小1,然后将1复制到大小为2的新数组中并填充项目2,将其增大到大小3并填充项目3,依此类推。n个实体中的第一个被复制n次,第二个被复制n-1次,依此类推,对于nn+1/2=On2个副本。但是,如果您使用一种乘法扩展技术,Go的append实现会将其应用到OLOGN拷贝。但每一个都会复制更多的字节。它最终被打开,摊销,看

与切片一起使用的空间显然处于打开状态。链表方法使用的空间也处于打开状态,尽管记录现在至少需要一个向前指针,因此每个记录都需要一些额外的空间

因此,就构建数据所需的时间和保存数据所需的空间而言,两者都有可能。最终得到的总内存需求是相同的。首先,主要的区别在于链表方法不需要连续内存

那么:当使用连续内存时,我们会损失什么?我们会得到什么

我们失去了什么 我们失去的东西是显而易见的。如果我们已经有碎片化的内存区域,我们可能无法获得正确大小的连续块。也就是说,考虑到:

使用:1 MB从底部开始,在底部+1米处结束 空闲:1MB从+1M开始,在+2M结束 使用:1MB等 免费:1 MB 已使用:1 MB 免费:1 MB 我们总共有6MB,3个已使用,3个免费。我们可以分配3个1MB块,但我们不能分配一个3MB块,除非我们能够以某种方式压缩三个使用的区域

由于Go程序往往在64 GB或更大的虚拟内存空间机器上的虚拟内存中运行,因此这并不是一个大问题。当然,每个人的情况都不同,所以如果你真的受到虚拟机的限制,这是一个真正的问题。其他语言有压缩GC来处理这个问题,未来的Go实现至少在理论上可以使用压缩GC

我们得到了什么 第一个好处也是显而易见的:我们不需要在每条记录中使用指针。这节省了一些空间,具体数量取决于指针的大小,是否使用单链接列表,等等。让我们假设2个8字节的指针,或者每个记录16字节。乘以1000万条记录,我们在这里看起来相当不错:我们节省了160兆字节。Go的容器/列表实现使用双链接列表,在64位机器上,这是所需的每元素线程的大小

不过,一开始我们得到了一些不太明显的东西,而且是巨大的。因为Go是一种垃圾收集语言,所以GC必须在不同时间检查每个指针。切片方法每个记录没有额外的指针;链表方法有两个方面。这意味着GC系统可以避免检查1000万条记录中不存在的2000万个指针

结论 有时需要使用容器/列表。如果你的算法真的需要一个列表
d是非常清楚的方式,这样做,除非和直到它被证明是一个问题,在实践中。或者,如果您的项目可以位于某些列表集合中,则实际上共享的项目中,有些在X列表中,有些在Y列表中,有些在这两个列表中,这将调用列表样式容器。但是,如果有一种简单的方法可以将某个内容表示为列表或切片,那么首先选择切片版本。由于Go内置了切片,因此您还可以获得第一个链接中提到的类型安全性/清晰度。

我看到有人否决了这个问题。你能至少解释一下你为什么这么做吗?我真的不明白为什么分配和重新调暗一个大的连续内存块比使用几个较小的非连续内存块更好。谢谢。切片和链接列表是具有不同特征的不同事物,如果您的解决方案更适合您定义的“使用链接列表更好”,那么就这样做吧。我看这里没有问题。谢谢@torek。GC开销确实是我忽略了的东西,并且肯定是使用双链接列表的缺点之一。