MySQL threadsafe verwenden?

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Volvic
User
Beiträge: 30
Registriert: Donnerstag 14. Juni 2007, 05:18

hi,

ich stehe vor dem problem das MySQL (das protkoll) nur eine aktion je connection gleichzeitig ausführen kann (was mich auch eigentlich garnicht stört). ich benutze in meinem programm 10 worker threads die manchmal eine mysql aktion ausführen müssen. als eigene lösung dachte ich mir das ich einfach eine Queue.Queue benutze und einen extra thread der diese Queue permanent abfrägt. das problem wäre dann aber wenn ich werte aus einer mysql tabelle lesen möchte eben mit dieser methode blöd darstehen würde.
hat jemand vielleicht eine bessere idee? ich dachte auch schon evtl an das locken der threads, was ich aber nur ungern machen möchte.

PS: ich verwende für die verbindung MySQLdb

mit freundlichen grüßen
- Volvic
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich hab' dir mal einen möglichen Ansatz skizziert. Du bräuchtest nur noch einen Datenbank-Thread, welcher die Anfragen in einer Queue entgegen nimmt und diese nacheinander mit "commit" abarbeitet.

In "SQLStatement" kannst du anfragen stecken, die eine Änderung durchführen, in "SQLExpression" eine Anfrage, die ein Ergebnis liefert. Dieses wird dann in "result" abgelegt.

Nach Abarbeitung einer Anfrage wird "done" gesetzt um der anfragend Thread mitzuteilen, dass die Anfrage abgearbeitet ist.

Das "_before" habe ich einfach mal aus Gründen der Symmetrie eingefügt, vielleicht braucht man es ja bei Gelegenheit noch mal.

Code: Alles auswählen

import threading

class SQLRequest(object):
    def __init__(self, sql):
        self.sql = sql
        self.done = threading.Event()

    def commit(self, dbcursor, dbparams):
        self._before(dbcursor, dbparams)
        dbcursor.execute(self.sql, dbparams)
        self._after(dbcursor)
        self.done.set()

    def _before(self, dbcursor, dbparams):
        pass

    def _after(self, dbcursor):
        pass

class SQLStatement(SQLRequest):
    def _after(self, dbcursor):
        dbcursor.commit()

class SQLExpression(SQLRequest):
    def _after(self, dbcursor):
        self.result = dbcursor.fetchall()
Volvic
User
Beiträge: 30
Registriert: Donnerstag 14. Juni 2007, 05:18

dankeschön, werde ich nun mal ausprobieren :)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Volvic hat geschrieben:ich benutze in meinem programm 10 worker threads die manchmal eine mysql aktion ausführen müssen.
Hallo Volvic!

CherryPy gibt dir die Möglichkeit, eine Connection an einen Thread zu binden. Damit kannst du eine Verbindung zum MySQL-Server **je** Thread aufmachen. Somit hast du dann 10 Threads und 10 Verbindungen offen. -- ideal!

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import cherrypy

# Ganz egal wo im Programm du bist. "cherrypy.thread_data" enthält immer nur
# die **im aktuellen Thread** zugewiesenen Daten. Das wird im Hintergrund 
# durch die Verwendung von "threading.local" erreicht. Dieser Platz ist dadurch
# ideal dafür geeignet, eine Connection zu einer MySQL-Datenbank aufzunehmen.
thread_data = cherrypy.thread_data

# Wenn es die Verbindung noch nicht gibt, dann Verbindung initialisieren...
if not hasattr(thread_data, "conn"):
    thread_data.conn = "Irgendeine Datenbankverbindung"

# Verbindung verwenden...
print thread_data.conn
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

...Hier noch ein kleiner Nachtrag:

Da steht alles drinn, was man so brauchen könnte und wie man die Sache am Schönsten angehen kann.

http://tools.cherrypy.org/wiki/Databases

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Volvic
User
Beiträge: 30
Registriert: Donnerstag 14. Juni 2007, 05:18

vielen dank :)
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import cherrypy

# Ganz egal wo im Programm du bist. "cherrypy.thread_data" enthält immer nur
# die **im aktuellen Thread** zugewiesenen Daten. Das wird im Hintergrund 
# durch die Verwendung von "threading.local" erreicht. Dieser Platz ist dadurch
# ideal dafür geeignet, eine Connection zu einer MySQL-Datenbank aufzunehmen.
thread_data = cherrypy.thread_data

# Wenn es die Verbindung noch nicht gibt, dann Verbindung initialisieren...
if not hasattr(thread_data, "conn"):
    thread_data.conn = "Irgendeine Datenbankverbindung"

# Verbindung verwenden...
print thread_data.conn
Moin,
eine Frage hab ich noch dazu.
Wie kann ich die 10 offenen Verbindungen die cherrypy beim start erstellt dann wieder schließen. Bzw. worum es mir geht ist eher wie kann ich bei einem Shutdown des cherrypy Servers die ganzen offenen Verbindungen schließen?
Denn cherrypy kennt keine möglich eine bestimmte Funktion vor dem shutdown auszuführen.
Oder irre ich mich da?

Danke.

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

Damaskus hat geschrieben:worum es mir geht ist eher wie kann ich bei einem Shutdown des cherrypy Servers die ganzen offenen Verbindungen schließen?
Hallo Damaskus!

Ich denke mal, dass die Connections beim Zerstören von *thread_data* automatisch geschlossen werden. -- Gleich wie beim File-Objekt. Dieses wird ja auch geschlossen, auch wenn man *close()* nicht explizit vor dem Ende eines Programmes aufruft.

Hattest du Probleme die darauf hinweisen, dass die Connections nicht geschlossen werden?

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

Ansonsten könnte man das mit dem `atexit`-Modul machen.
Benutzeravatar
Damaskus
Administrator
Beiträge: 995
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

gerold hat geschrieben:
Damaskus hat geschrieben:worum es mir geht ist eher wie kann ich bei einem Shutdown des cherrypy Servers die ganzen offenen Verbindungen schließen?
Hallo Damaskus!

Ich denke mal, dass die Connections beim Zerstören von *thread_data* automatisch geschlossen werden. -- Gleich wie beim File-Objekt. Dieses wird ja auch geschlossen, auch wenn man *close()* nicht explizit vor dem Ende eines Programmes aufruft.

Hattest du Probleme die darauf hinweisen, dass die Connections nicht geschlossen werden?

lg
Gerold
:-)
Hallo Gerold,
es war eher nur ein Gedankengang von mir.
Ich hab das heute mal getestet und es ist so wie du vermutet hast das die Connections mit dem zerstören von "thread_data" geschlossen werden.

Allerdings ergibt sich jetzt ein neues Problem. Die Connections die offen sind, bleiben bei MySQL dauerhaft im "sleep" Status was mir wiederum nicht gefällt.
Aber dazu bastel ich mir noch eine Kontroll/Steuerungsfunktion.

Gruß
Damaskus
Antworten