Datenbankzugriffe mit mehrern Threads

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Hallo zusammen, mich beschäftigt derzeit ein mutithreading-Problem
bzgl der Zugriffe auf auf eine Datenbank über psycopg2.

Laut Python Database API Specification: PEP249 gilt für
Datenbankmodule wie psycopg2 mit thread-safety level 2:
Threads may share the module and connections.
Das hab ich dann auch so innerhalb eines größeren Projects so umgestzt und hab
dann bei starken Belastungstests festgestellt, dass sich die cursor bei den Datenbankzugriffen in die Quere kommen können.

Bekomme unterschiedliche OperationalErrors die zu erkennen geben das die übermittelten SQL-Statements über den Jordan sind.

Diese Mailinglist von Gregorio und mein kleines Testprogramm bestätigen das Problem.

Code: Alles auswählen

import threading
import psycopg2

THREADS = 20

conn_string = "host=... port=... "

dbConnection  = psycopg2.connect(conn_string)

def test():
    cursor = dbConnection.cursor()
    cursor.execute("select name from components where id = %i" % 1)
    sql_result = cursor.fetchall ()
  
for i in range(THREADS):
    t=threading.Thread(target=test)
    t.start()
Ich frag mich jetzt wo mein Verständisproblem bzgl der Spec ist,
wenn da steht, dass sich die Threads die Connection teilen dürfen
und ich jedem Thread ein eigenes Cursor-objekt in die Hand drücke,
müsste das doch eigentlich gehen.

Weiß einer den genauen Hintergrund? Und/Oder was ich falsch verstanden habe? Ist psycopg vielleicht doch nicht Level 2 safety?
Ich möchte halt gerne wissen wie es zu solchen crashes kommen kann wenn
ich doch angeblich die connection sharen darf.

Lösungswege wie Locks() oder ThreadedConnectionPool sind mir bekannt.


Vielen Dank im voraus
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Zap hat geschrieben:Datenbankmodule wie psycopg2 mit thread-safety level 2:
Threads may share the module and connections.
Weiß einer den genauen Hintergrund?
Hallo Zap!

Ich finde, dass "thread-safety" nicht auf 2 stehen dürfte. Das ist eine Irreführung der Benutzer.
http://lists.initd.org/pipermail/psycop ... 04378.html

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Ah, jetzt weiß ich wenigstens wo ich dran bin.
Danke, brauchte eine konkrete Antwort um wieder ruhig schlafen zu können ;)

Interessant, dass das Statement auch schon knapp 1,5 Jahre alt ist.
Hätte das nicht umbedingt für Aktuell gehalten, aber gut.

Ein Frage hätte ich aber doch noch, und zwar habe ich mich für die Lösung entschieden den ThreadedConnectionPool zu verwenden.
Wenn ich diesen nun auf einen Max-Wert setze und diesen überschreite
bekomme ich eine PoolError Exception und für den Thread ist's gelaufen.

Gibt es eine blockierende alternative, anstatt den Pool die ganze Zeit zu pollen?
Ich empfinde meine aktuelle Lösung nämlich als ehr unschön.

Code: Alles auswählen

while True:
    try: 
        conn = conn_pool.getconn()
        break
    except PoolError:
        pass
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Zap hat geschrieben:Gibt es eine blockierende alternative, anstatt den Pool die ganze Zeit zu pollen? Ich empfinde meine aktuelle Lösung nämlich als ehr unschön.

Code: Alles auswählen

while True:
    try: 
        conn = conn_pool.getconn()
        break
    except PoolError:
        pass
Hallo Zap!

Ich habe noch keine Erfahrung mit dem ThreadedConnectionPool, aber deine Lösung sieht ja gar nicht mal so schlecht aus. Ich würde nur noch ein ``time.sleep(0.1)`` in die Schleife einbauen, um die CPU, im Falle eines wiederholten PoolErrors, ein wenig zu entlasten.
Du könntest auch einen Timeout mit einbauen. Falls es wirklich mal sein sollte, dass du 30 sec. lang keine Connection bekommst, sollte das Programm irgendwie darauf reagieren können.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten