2013-08-15 5 views
10

Also, ich versuche, eine Anwendung zu schreiben, die Django als ORM verwendet, da es beide hinter den Kulissen Verarbeitung und ein einfach zu bedienendes Front-End tun müssen. Seine Kernfunktionalität ist die Verarbeitung von Daten, die sich in der Datenbank befinden, in einem Prozess mit hoher CPU (im Grunde Monte-Carlo-Simulationen), und ich möchte Multiprozessing implementieren, speziell mit Pool (ich bekomme 4 Prozesse). Im Grunde genommen mein Code wie folgt ausgeführt wird, mit etwa 20 Kindern der Eltern:Wie behandelt man die Parallelität von Python-Multiprocessing-Datenbanken, speziell mit Django?

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 

Mit dem Code als solche, erhalte ich intermittierend DatabaseError s oder PicklingError s. Ersteres hat normalerweise die Form "missformed database" oder "Verbindung zum MySQL-Server verloren", letzteres ist in der Regel "kann Model.DoesNotExist nicht picken". Sie sind zufällig, treten bei jedem Prozess auf und natürlich ist nichts an der DB selbst falsch. Wenn ich pool = Pool(proccesses=1) einstelle läuft es dann in einem einzigen Thread ganz gut. Ich gebe auch verschiedene Druckanweisungen ein, um sicherzustellen, dass die meisten tatsächlich ausgeführt werden.

Ich habe auch test an sich verändert:

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

die nur jede Iteration weniger als eine Sekunde vor dem Ausführen Pause macht, und es macht alles in Ordnung. Wenn ich das zufällige Intervall auf ungefähr 500ms heruntersetze, fängt es an zu agieren. Also, wahrscheinlich ein Nebenläufigkeitsproblem, oder? Aber mit nur 4 Prozessen schlagen. Meine Frage ist, wie löse ich das, ohne große Datenmengen vor der Zeit zu machen? Ich habe es sowohl mit SQLite als auch mit MySQL getestet, und beide haben Probleme damit.

+0

Da die Prozesse CPU-gebunden sind, warum dann Verwenden Sie keine 'multiprocessing.Lock', um alle Race-Bedingungen für die Datenbank zu vermeiden? – Bakuriu

Antwort

7

Okay, also habe ich festgestellt (mit Hilfe eines Freundes), dass das Problem ist, dass Django die gleiche Datenbankverbindung für alle Prozesse verwendet. Normalerweise, wenn Sie gleichzeitige DB-Anfragen haben, sind sie entweder im selben Thread (in diesem Fall GIL tritt ein) oder sie sind in separaten Threads, in welchem ​​Fall django verschiedene Datenbankverbindungen herstellt. Aber mit Multiprocessing erstellt Python Tiefdruck von allem, also gibt es die gleiche Datenbankverbindung zu den Unterprozessen und dann treten sie aufeinander, bis sie bricht.

Die Lösung besteht darin, eine neue Db-Verbindung innerhalb jedes Subprozesses auszulösen (was relativ schnell ist).

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 

Ging hin und her von dieser Linie, und nicht mit dieser Linie, und definitiv repariert alles.

+1

Danke! Ich habe früher Threads verwendet und bekam Probleme, als ich Multiprocessing einsetzte. Ihre Erklärung zwischen den beiden Fällen hat meinen Tag gemacht. – Mikuz

3

Eigentlich habe ich vor kurzem bekam die gleichen Probleme, und sehen diesen Beitrag: Django multiprocessing and database connections ... und nur die Verbindung Schließvorgang in Subprozesse aufrufen:

from django.db import connection 
connection.close()