【问题标题】:Python process abruptly killed during executionPython进程在执行期间突然终止
【发布时间】:2012-10-10 23:49:05
【问题描述】:

我是 python 新手,面临似乎是内存泄漏错误。 我编写了一个简单的脚本,它试图从 postgres 数据库中获取多个列,然后继续对这些列执行简单的减法并将结果存储在一个正在写入文件的临时变量中。我需要对数据库中的多对列执行此操作,并且我正在使用列表列表来存储不同的列名。

我会遍历这个列表的各个元素,直到列表用完。虽然我得到了前几列对的有效结果(有效我的意思是输出文件包含预期值),但程序在执行之间的某处突然被“杀死”。代码如下:

varList = [ ['table1', 'col1', 'col2'],
        ['table1', 'col3', 'col4'],
        ['table2', 'col1', 'col2'],
        # ..
        # and many more such lines
        # ..
        ['table2', 'col3', 'col4']]

try:

    conn = psycopg2.connect(database='somename', user='someuser', password='somepasswd')

    c = conn.cursor()

    for listVar in varList:
        c.execute("SELECT %s FROM %s" %(listVar[1], listVar[0]))

        rowsList1 = c.fetchall();

        c.execute("SELECT %s FROM %s" %(listVar[2], listVar[0]))

        rowsList2 = c.fetchall();

        outfile = file('%s__%s' %(listVar[1], listVar[2]), 'w')

        for i in range(0, len(rowsList1)):
            if rowsList1[i][0] == None or rowsList2[i][0] == None:
                timeDiff = -1

            else:
                timestamp1 = time.mktime(rowsList1[i][0].timetuple())
                timestamp2 = time.mktime(rowsList2[i][0].timetuple())
                timeDiff = timestamp2 - timestamp1

            outfile.write(str(timeDiff) + '\n')

        outfile.close();

    del rowsList1, rowsList2

#numpy.savetxt('output.dat', column_stack(rows))

except psycopg2.DatabaseError, e:
    print 'Error %s' % e
    sys.exit(1)

finally:
    if conn:
        conn.close()

我最初的猜测是存在某种形式的内存泄漏,为了解决这个问题,我在两个大数组上添加了一个 del 语句,希望内存被正确收集。这一次,我得到了稍微好一点的输出(稍微好一点是指为 db 列对创建了更多的输出文件)。 但是,在第 10 对或第 11 对列之后,我的程序又被“杀死”了。有人可以告诉我这里可能出了什么问题。有没有更好的方法来完成这项工作? 任何帮助表示赞赏。

PS:我知道这是一个相当低效的实现,因为我循环了很多次,但我需要一些快速而肮脏的东西来证明概念。

【问题讨论】:

  • 您希望在这里处理多少数据?
  • cursor.fetchall() 可能是杀手,因为它会尝试在核心中复制整个数据库。 fetchone() 可能是你想要的,因为你一次处理一行。
  • 你有什么理由不能让数据库在 SQL 中计算你的时间差异?然后你可以遍历光标并将值写入输出文件。
  • @GregHewgill:数据库表有大约 250000-260000 行。我正在尝试一次获取所有这些。
  • @msw:我将更改代码以使用 numpy 或类似的东西一次处理整个列表。所以从长远来看,我需要像 fetchall() 这样的东西。有没有更便宜的替代品?

标签: python memory memory-leaks process psycopg2


【解决方案1】:

我认为这里的问题是,当您应该使用 sql 查询选择所需内容时,您选择了所有内容,然后在应用程序代码中对其进行过滤。如果您在 sql 查询中选择您想要的内容,如下所示:

对于 varlist 中的 listvar: select listvar[1], listvar[2] from listvar[0] where listvar[1] is not null and listvar[2] is not null

# then...

timeDiff = {}
for row in rows:
    timestamp1 = time.mktime(row[0].timetuple())
    timestamp2 = time.mktime(row[0].timetuple())
    timeDiff[identifier] = timestamp2 - timestamp1 #still need to assoc timediff with row... maybe you need to query a unique identifyer also?

#and possibly a separate... (this may not be necessary depending on your application code.  do you really need -1's for irrelevant data or can you just return the important data?)

select listvar[1], listvar[2] from listvar[0] where listvar[1] is null or listvar[2] is null

for row in rows:
    timeDiff[identifier] = -1 # or None

【讨论】:

  • 感谢您的回答。我看不出一次选择第 1 列和第 2 列如何改善这种情况,而不是单独选择它们。你能解释一下吗?谢谢。
  • 好问题。这允许数据库引擎完成过滤数据的工作。使用游标意味着您不会一次性获得第 1 列和第 2 列,而是只会获得已由数据库引擎预过滤的符合您的条件的列子集。数据库引擎在排序和过滤数据方面通常比客户端代码更有效。
  • 另外,你的两条 c.fetchall() 行实际上使处理数据所需的内存量增加了一倍。 @msw 在他的评论中指出了 fetchall() 的问题。使用 fetchall() 基本上否定了使用游标的好处。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-28
  • 1970-01-01
  • 2013-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多