Multiprocessing + psycopg2 僵尸子进程

3
我正在尝试使用psycopg和多进程插入和更新几百万行数据。根据http://initd.org/psycopg/docs/usage.html#thread-and-process-safety中的文档,每个子进程都有自己的连接到数据库。
但在执行过程中,只有一个子进程在运行,而其他进程则变成僵尸进程。脚本本身非常简单,以下是削减版本。
import os
import psycopg2

from multiprocessing import Process


def _target(args):
    # Each forked process will have its own connection
    # http://initd.org/psycopg/docs/usage.html#thread-and-process-safety
    conn = get_db_connection()

    # Stuff seems to execute till this point in all the children
    print os.getpid(), os.getppid()

    # Do some updates here. After this only one child is active and running
    # Others become Zombies after a while.


if __name__ == '__main__':
    args = "Foo"
    for i in xrange(3):
        p = Process(target=_target, args=(args,))
        p.start()

我也查看了 pg_locks 表,想确定是否存在升级锁,但似乎并不是这种情况。我是否漏掉了一些明显的东西?


get_db_connection函数是做什么用的?它是创建一个新的连接还是返回一个共享连接?根据你提供的文档,它应该是创建一个新的连接。 - Philip Southam
Philip,不,它不使用共享连接。每个分叉的子进程都会创建一个新的连接和游标集。 (应该是create_db_connection()) - sudharsh
1个回答

0

你的进程变成僵尸进程,因为任务已经完成,但进程未加入。

我通过这个单一测试重现了你的问题(我添加了休眠以模拟长时间运行的任务):

import os
import time
from multiprocessing import Process

def _target(args):
    print os.getpid(), os.getppid()
    time.sleep(2)
    print os.getpid(), "will stop"

if __name__ == '__main__':
    args = "Foo"
    for i in xrange(3):
        p = Process(target=_target, args=(args,))
        p.start()
    import time
    time.sleep(10)

当执行此操作时,在3个进程打印它们将停止后,它们在ps视图中变为僵尸进程(它们不再移动,但实际上并未死亡,因为父进程仍然持有它们)。

如果我用以下内容替换主要部分,则不再有僵尸进程:

if __name__ == '__main__':
    args = "Foo"
    processes = []
    for i in xrange(3):
        p = Process(target=_target, args=(args,))
        processes.append(p)
        p.start()
    for p in processes:
        p.join()
    import time
    time.sleep(10)

Cedric,我的问题是只有一个子进程在运行,而其他子进程变成了僵尸进程。 顺便说一下,问题最终被证实是Postgres中的死锁。 - sudharsh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接