Python 在itertools.combines命令后内核死亡

Python 在itertools.combines命令后内核死亡,python,jupyter-notebook,itertools,Python,Jupyter Notebook,Itertools,我正在使用 Python 3.5.2 | Anaconda 4.3.0(x86_64)|(默认,2016年7月2日,17:52:12) [GCC 4.2.1兼容苹果LLVM 4.2(clang-425.0.28)] 我必须运行以下命令 longList = list(combinations(range(2134), 3)) 我知道这个长度大约是16亿。当我运行它时,过了一段时间,我收到消息“内核似乎已死亡。它将自动重新启动。” 使用3而不是2运行相同的命令时不会出现任何问题: longLis

我正在使用 Python 3.5.2 | Anaconda 4.3.0(x86_64)|(默认,2016年7月2日,17:52:12) [GCC 4.2.1兼容苹果LLVM 4.2(clang-425.0.28)]

我必须运行以下命令

longList = list(combinations(range(2134), 3))
我知道这个长度大约是16亿。当我运行它时,过了一段时间,我收到消息“内核似乎已死亡。它将自动重新启动。”

使用3而不是2运行相同的命令时不会出现任何问题:

longList = list(combinations(range(2134), 2))

在这种情况下,我可以/应该做什么?

您的内存可能已用完。快速计算:64位整数或指针的大小为8字节。有16亿个组合是元组。每个元组包含三个整数。这意味着您需要至少1.6E9*(1+3)*8B=48GB的内存

然而,由于Python的内存模型,您将需要比这多得多的东西:每个整数实际上是一个对象,因此我们需要1个机器字作为列表中的指针,可能需要3或4个机器字作为对象本身(我不确定细节,请阅读CPython源代码了解实际的对象布局)。tuple对象也会有开销。我假设每个对象都有两个词。因此,我们必须额外增加1.6E9*(3+1)*2*8B=95GB的额外开销,使其总计达到143GB左右

这可以通过使用密集的numpy数组来避免,因为它使用的是实整数,而不是对象。这消除了整数和元组对象的所有开销,因此我们“只”需要1.6E9*3*8B=35GB

我假设您运行的硬件没有那么多内存

您的
组合(…,2)
调用不是问题,因为它只生成大约200万个元组,其内存需求在MB范围内(2.2E6*(1+4+2*3)*8B=180MB)。作为一个numpy阵列,我们只需要2.2E6*2*8B=33MB

那么这里的解决方案是什么

  • 在规模上,像内存模型这样的低级细节甚至对Python也非常相关
  • 使用numpy可以显著减少内存使用,通常减少4倍。如果您使用较小的类型,例如
    dtype='int16'
    ,则会增加减少4的因素
  • 仔细想想,您是否需要急切地将
    组合()
    转换为一个列表,或者您是否可以懒洋洋地使用迭代器,或者将迭代器分成更小的块

谢谢你,阿蒙。这是有道理的。您建议我如何将compositions()迭代器分解成几部分?@Gordon您可以使用
list(itertools.islice(iterator,n))
一次选择接下来的n个项。