如何处理Python多处理数据库并发,特别是与django?

时间:2013-08-15 20:26:54

标签: python sql django multiprocessing pool

所以,我正在尝试编写一个使用django作为其ORM的应用程序,因为它需要做一些幕后处理和易于使用的前端。它的核心功能是处理数据库中的数据,在高CPU过程中(基本上是monte carlo模拟),我想实现多处理,特别是使用Pool(我得到4个进程)。基本上我的代码就是这样运行的,父代大约有20个孩子:

assorted import statements to get the django environment in the script
from multiprocessing import Pool
from random import random
from time import sleep

def test(child):
    x=[]
    print child.id
    for i in range(100):
        print child.id, i
        x.append(child.parent.id) #just to hit the DB
    return x

if __name__ == '__main__':
    parent = Parent.objects.get(id=1)
    pool = Pool()
    results = []
    results = pool.map(test,parent.children.all())
    pool.close()
    pool.join()
    print results

使用这样的代码,我得到间歇DatabaseErrorPicklingError s。前者通常是“格式错误的数据库”或“与MySQL服务器失去连接”的形式,后者通常是“不能泡菜型号.DoesNotExist”。它们是随机的,随任何进程发生,当然DB本身没有任何问题。如果我设置pool = Pool(proccesses=1)然后它运行,在单个线程中就好了。我还会输入各种打印语句,以确保它们中的大部分都在运行。

我也一直在将test更改为:

def test(child):
    x=[]
    s= random()
    sleep(random())
    for i in range(100):
        x.append(child.parent.id)
    return x

这使得每次迭代在运行之前暂停不到一秒,并且它使一切正常。如果我将随机间隔缩短到大约500毫秒,它就会开始起作用。那么,可能是一个并发问题,对吧?但只有4个进程击中。我的问题是如何在不提前大量转储数据的情况下解决这个问题?我用SQLite和MySQL测试了它,两者都遇到了麻烦。

2 个答案:

答案 0 :(得分:7)

好的,所以我确定(在朋友的帮助下)问题是django正在为所有进程使用相同的数据库连接。通常,当你有并发数据库请求时,它们要么在同一个线程中(在这种情况下GIL会启动),要么它们位于不同的线程上,在这种情况下,django会建立不同的数据库连接。但是通过多处理,python会生成所有内容的深层次,所以它将相同的数据库连接传递给子进程,然后它们互相踩到它们就会中断。

解决方案是从每个子进程内触发一个新的数据库连接(相对较快)。

from django import db
...
def sub_process():
    db.close_connection()
    #the rest of the sub_process' routines

#code that calls sub_process with the pool

从那条线上来回走动,没有那条线,并且肯定能解决所有问题。

答案 1 :(得分:3)

其实我最近遇到了同样的问题,看到这篇文章:Django multiprocessing and database connections ... 并只调用子进程中的连接关闭操作:

from django.db import connection 
connection.close()