Python每执行98次就会面临开销?

Python每执行98次就会面临开销?,python,pandas,overhead,Python,Pandas,Overhead,我有一个大数据库,我只想给一个新列分配一个常量。第一次处决时(1至97);一切正常,代码运行速度很快。然后,内存在迭代98时启动,然后就可以了,直到迭代196(98次迭代之后),RAM再次启动,然后循环继续在每个i处启动内存,其中i是98的乘法 我猜神秘的数字98可能会因你的电脑而异。 为了重现问题,您可能必须更改数据库大小 这是我的密码 Edit:我认为这不是垃圾收集,因为gc.isenabled()在代码末尾返回False import pandas as pd import numpy a

我有一个大数据库,我只想给一个新列分配一个常量。第一次处决时(1至97);一切正常,代码运行速度很快。然后,内存在迭代98时启动,然后就可以了,直到迭代196(98次迭代之后),RAM再次启动,然后循环继续在每个
i
处启动内存,其中
i
是98的乘法

我猜神秘的数字98可能会因你的电脑而异。 为了重现问题,您可能必须更改数据库大小

这是我的密码

Edit:我认为这不是垃圾收集,因为
gc.isenabled()
在代码末尾返回
False

import pandas as pd
import numpy as np

n = 2000000
data = pd.DataFrame({'a' : range(n)})
for i in range(1, 100):
    data['col_' + str(i)] = np.random.choice(['a', 'b'], n)

gc.disable()
for i in range(1, 600):
    data['test_{}'.format(i)] = i
    print(str(i)) # slow at every i multiplication of 98

gc.isenabled()
> False
这是我的内存使用情况,峰值出现在迭代
i*98
(其中
i
是一个整数)

我使用的是Windows10,Python 3.6.1 | Anaconda4.4.0 | pandas 0.24.2

我有16 GB RAM和8核CPU


首先,我想确认在禁用16GB RAM和GC的Ubuntu上的相同行为。因此,这绝对不是GC或Windows内存管理的问题

其次,在我的系统上,每99次迭代后,速度就会减慢:99次之后、198次之后、297次之后,等等。无论如何,我有一个相当有限的交换文件,所以当RAM+交换被填满时,它会崩溃,并出现以下堆栈跟踪:

294
295
296
297
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/indexes/base.py", line 2657, in get_loc
    return self._engine.get_loc(key)
  File "pandas/_libs/index.pyx", line 108, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 132, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 1601, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 1608, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'test_298'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/internals/managers.py", line 1053, in set
    loc = self.items.get_loc(item)
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/indexes/base.py", line 2659, in get_loc
    return self._engine.get_loc(self._maybe_cast_indexer(key))
  File "pandas/_libs/index.pyx", line 108, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 132, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 1601, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 1608, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'test_298'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "py-memory-test.py", line 12, in <module>
    data['test_{}'.format(i)] = i
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/frame.py", line 3370, in __setitem__
    self._set_item(key, value)
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/frame.py", line 3446, in _set_item
    NDFrame._set_item(self, key, value)
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/generic.py", line 3172, in _set_item
    self._data.set(key, value)
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/internals/managers.py", line 1056, in set
    self.insert(len(self.items), item, value)
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/internals/managers.py", line 1184, in insert
    self._consolidate_inplace()
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/internals/managers.py", line 929, in _consolidate_inplace
    self.blocks = tuple(_consolidate(self.blocks))
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/internals/managers.py", line 1899, in _consolidate
    _can_consolidate=_can_consolidate)
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/internals/blocks.py", line 3149, in _merge_blocks
    new_values = new_values[argsort]
MemoryError
我想这正是我们要找的

每次执行
insert
时,都会创建新块。当块数超过某个限制时,将执行额外工作(合并)。代码中的100个块限制和我们获得的98-99左右的经验数字之间的差异可以解释为存在一些额外的数据帧元数据,这也需要一些空间

UPD:为了证明这一假设,我尝试改变100->1000000,效果很好,没有性能差距,没有
内存错误。但是,没有公共API在运行时修改此参数,它只是硬编码的


UPD2:提交了一个到
pandas
,因为
MemoryError
看起来不适合这样一个简单的程序。

我怀疑这是垃圾收集。@Barmar我可以得到自动垃圾收集在迭代98(峰值后)后清理内存的结果但我不明白为什么在I=98时内存会出现颠簸,它可能正在重建一个哈希表,因为它跨越了各种大小边界。所以它暂时有两个副本,然后旧的副本变成了垃圾。@Barmar我是python的新手,你能详细说明一下吗?那么可能的解决方案是什么呢?为什么at
i=98
会复制数据,而不是at
i=97
i=99
?这很神秘。为了消除这种行为,我应该将数字100增加到10000?这是一个
pandas
核心代码,所以答案是肯定的,您可以在
pandas
发行版中本地更改此数字,但在运行时没有公共API来更改它。我甚至试着检查它,一切都进行得很顺利,没有记忆错误,更新了答案我在我安装的pandas Package中没有找到
internal
文件夹,所以我无法修改它…可能你在错误的目录中查找。试着用这里的问答找出熊猫的位置。此外,Windows分发结构可能不同,因此请尝试在资源管理器中搜索
managers.py
文件。我在AppData\\Local\\Continuum\\Anaconda3\\lib\\site packages\\pandas中搜索
def insert(self, loc, item, value, allow_duplicates=False):
    ...
    self._known_consolidated = False

    if len(self.blocks) > 100:
        self._consolidate_inplace()