【发布时间】:2019-10-18 12:06:55
【问题描述】:
当通过 sqlalchemy 和 pandas to_sql 和指定的卡盘大小将一个巨大的 pandas 数据框插入 sqlite 时,我会遇到内存错误。
起初我认为这是to_sql 的问题,但我尝试了一种解决方法,我使用for i in range(100): df.iloc[i * 100000:(i+1):100000].to_sql(...) 而不是使用chunksize,但仍然导致错误。
在某些情况下,似乎存在内存泄漏,通过 sqlalchemy 重复插入到 sqlite。
我很难通过一个最小的示例来复制转换数据时发生的内存泄漏。但这非常接近。
import string
import numpy as np
import pandas as pd
from random import randint
import random
def make_random_str_array(size=10, num_rows=100, chars=string.ascii_uppercase + string.digits):
return (np.random.choice(list(chars), num_rows*size)
.view('|U{}'.format(size)))
def alt(size, num_rows):
data = make_random_str_array(size, num_rows=2*num_rows).reshape(-1, 2)
dfAll = pd.DataFrame(data)
return dfAll
dfAll = alt(randint(1000, 2000), 10000)
for i in range(330):
print('step ', i)
data = alt(randint(1000, 2000), 10000)
df = pd.DataFrame(data)
dfAll = pd.concat([ df, dfAll ])
import sqlalchemy
from sqlalchemy import create_engine
engine = sqlalchemy.create_engine('sqlite:///testtt.db')
for i in range(500):
print('step', i)
dfAll.iloc[(i%330)*10000:((i%330)+1)*10000].to_sql('test_table22', engine, index = False, if_exists= 'append')
这是在 Google Colab CPU 环境中运行的。
数据库本身不会导致内存泄漏,因为我可以重新启动我的环境,并且之前插入的数据仍然存在,并且连接到该数据库不会导致内存增加。问题似乎是在某些条件下通过循环 to_sql 或一个 to_sql 重复插入并指定了夹头大小。
有没有一种方法可以运行此代码而不会最终增加内存使用量?
编辑:
要完全重现错误,请运行此笔记本
https://drive.google.com/open?id=1ZijvI1jU66xOHkcmERO4wMwe-9HpT5OS
笔记本要求您将此文件夹导入 Google Drive 的主目录
https://drive.google.com/open?id=1m6JfoIEIcX74CFSIQArZmSd0A8d0IRG8
笔记本还会挂载您的 Google 驱动器,您需要授权它访问您的 Google 驱动器。由于数据托管在我的 Google 驱动器上,因此导入数据不应占用您分配的任何数据。
【问题讨论】:
-
Alex Martelli says, "唯一真正可靠的方法是确保大量但临时的内存使用完成后确实将所有资源返回给系统,这是在子进程中进行该使用,这是否需要内存的工作然后终止。”
-
是的,您可以尝试将占用大量内存的代码封装在一个函数中,然后使用
multiprocessing在单独的进程中调用该函数。有一个example here。 -
@unutbu 不能解释这种情况,因为那里引用的现象不会导致内存错误。这可能是
to_sql方法中的内存泄漏 -
@SantoshGupta7 好吧,多处理创建了独立的python 进程,因此如果不做一些工作就没有共享状态。不过,一般来说,如果使用多处理,您应该尽可能避免共享状态。
标签: python pandas sqlite memory-leaks sqlalchemy