因此,我正在尝试编写一个使用 django 作为其 ORM 的应用程序,因为它既需要进行一些幕后处理,又需要一个易于使用的前端。它的核心功能是在高 CPU 进程(基本上是蒙特卡洛模拟)中处理数据库中的数据,我想实现多处理,特别是使用 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
使用这样的代码,我会间歇性地遇到 DatabaseError
或 PicklingError
。前者通常是“数据库格式错误”或“与 MySQL 服务器失去连接”的形式,后者通常是“无法 pickle model.DoesNotExist”。它们是随机的,发生在任何进程中,当然数据库本身没有任何问题。如果我设置 pool = Pool(processes=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 对其进行了测试,但都遇到了这个问题。
最佳答案
好的,所以我确定(在 friend 的帮助下)问题是 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
在有那条线和没有那条线之间来回走动,肯定能解决所有问题。
关于python - 如何处理 Python 多处理数据库并发,特别是使用 django?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18261195/