【问题标题】:Kernel dies after itertools.combinations command内核在 itertools.combinations 命令后死亡
【发布时间】:2018-12-11 17:15:02
【问题描述】:

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

我必须运行以下命令

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

我知道这个长度大约是 16 亿。当我运行它时,一段时间后我收到消息“内核似乎已经死机。它将自动重新启动。”

运行 3 个而不是 2 个的相同命令没有任何问题:

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

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

【问题讨论】:

    标签: python jupyter-notebook itertools


    【解决方案1】:

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

    但是,由于 Python 的内存模型,您需要的数量可能不止于此:每个整数实际上都是一个对象,因此列表中的指针需要 1 个机器字,对象本身可能需要 3 或 4 个机器字(我不确定细节,请阅读 CPython 源代码以了解实际对象布局)。元组对象也会有开销。我假设每个对象都有两个词开销。所以我们必须额外增加 1.6E9 * (3 + 1) * 2 * 8B = 95GB 额外开销,总共大约 143GB。

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

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

    您的combinations(..., 2) 调用没有问题,因为它只产生大约 200 万个元组,其内存要求在兆字节范围内 (2.2E6 * (1 + 4 + 2*3) * 8B = 180MB)。作为一个 numpy 数组,我们只需要 2.2E6 * 2 * 8B = 33MB。

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

    • 在规模上,内存模型等低级细节即使对于 Python 也非常重要
    • 使用 numpy 可以显着减少内存使用量,通常减少 4 倍。如果您使用更小的类型,例如 dtype='int16' 会减少 4 倍。
    • 认真考虑是否需要急切地将 combinations() 转换为列表,或者是否可以延迟使用迭代器或以更小的块形式使用迭代器

    【讨论】:

    • 谢谢阿蒙。这是有道理的。你会建议我如何将组合()迭代器分解成碎片?
    • @Gordon 你可以例如使用list(itertools.islice(iterator, n)) 一次选择接下来的 n 项。
    猜你喜欢
    • 2020-04-06
    • 1970-01-01
    • 2022-11-27
    • 2022-12-17
    • 2022-01-24
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 2020-02-28
    相关资源
    最近更新 更多