webentwicklung-frage-antwort-db.com.de

Was ist die beste Lösung für das Pooling von Datenbankverbindungen in Python?

Ich habe einige benutzerdefinierte DAO-ähnliche Klassen entwickelt, um einige sehr spezielle Anforderungen für mein Projekt zu erfüllen, das ein serverseitiger Prozess ist, der in keiner Art von Framework ausgeführt wird.

Die Lösung funktioniert hervorragend, außer dass ich jedes Mal, wenn eine neue Anfrage gestellt wird, eine neue Verbindung über MySQLdb.connect herstelle.

Was ist die beste "Drop-in" -Lösung, um dies auf die Verwendung von Verbindungspools in Python umzustellen? Ich stelle mir so etwas wie die gängige DBCP-Lösung für Java vor.

Der Prozess ist langwierig und hat viele Threads, die Anfragen stellen müssen, aber nicht alle gleichzeitig. Insbesondere erledigen sie eine Menge Arbeit, bevor sie einen Teil ihrer Ergebnisse kurz ausschreiben.

Bearbeitet, um hinzuzufügen: Nach einigem Suchen habe ich anitpool.py gefunden, das anständig aussieht, aber da ich relativ neu in Python bin, möchte ich wohl nur sicherstellen, dass ich kein offensichtlicheres/idiomatischeres/verpasse. bessere lösung.

31
John

IMO, die "naheliegendere/idiomatischere/bessere Lösung" besteht darin, einen vorhandenen ORM zu verwenden, anstatt DAO-ähnliche Klassen zu erfinden.

Es scheint mir, dass ORMs beliebter sind als "rohe" SQL-Verbindungen. Warum? Denn Python ist OO und das Mapping von der SQL-Zeile auf das Objekt ist absolut notwendig. Es gibt nicht viele Fälle, in denen Sie sich mit SQL-Zeilen beschäftigen, die nicht Python-Objekten zugeordnet sind.

Ich denke, dass SQLAlchemy oder SQLObject (und das damit verbundene Verbindungspooling) die idiomatischere Pythonic-Lösung ist.

Pooling als separate Funktion ist nicht sehr üblich, da reines SQL (ohne Objektzuordnung) für komplexe, langwierige Prozesse, die vom Verbindungspooling profitieren, nicht sehr beliebt ist. Ja, pure SQL ist , wird jedoch immer in einfacheren oder kontrollierten Anwendungen verwendet, bei denen das Pooling nicht hilfreich ist.

Ich denke, Sie haben zwei Alternativen:

  1. Überarbeiten Sie Ihre Klassen, um SQLAlchemy oder SQLObject zu verwenden. Während dies auf den ersten Blick schmerzhaft erscheint [diese ganze Arbeit ist vergeudet], sollten Sie in der Lage sein, alle Konstruktionen und Gedanken zu nutzen, und es ist nur eine Übung zur Einführung einer weit verbreiteten ORM- und Pooling-Lösung.
  2. Rollen Sie Ihren eigenen einfachen Verbindungspool mit dem beschriebenen Algorithmus - einem einfachen Satz oder einer Liste von Verbindungen, die Sie durchlaufen. 
16
S.Lott

In MySQL?

Ich würde sagen, dass Sie sich nicht mit dem Verbindungspooling beschäftigen sollten. Sie sind oft eine Quelle von Problemen und mit MySQL bringen sie Ihnen nicht den Leistungsvorteil, auf den Sie hoffen. Dieser Weg ist unter Umständen politisch sehr anstrengend, weil es in diesem Bereich so viele bewährte Methoden gibt, die von Hand winken und Lehrbuchlaute über die Vorteile von Verbindungspooling sprechen.

Verbindungspools sind einfach eine Brücke zwischen der post-web-Ära zustandsloser Anwendungen (z. B. dem HTTP-Protokoll) und der prä-web-Ära von stateful langlebigen Stapelverarbeitungsanwendungen. Da Verbindungen in Datenbanken vor dem Web sehr teuer waren (da sich bisher niemand zu sehr darum kümmerte, wie lange eine Verbindung herstellte), entwickelten Post-Web-Anwendungen dieses Verbindungspoolschema, sodass für jeden Treffer kein so großer Verarbeitungsaufwand anfiel auf dem RDBMS.

Da MySQL eher ein RDBMS aus dem Web-Zeitalter ist, sind die Verbindungen extrem leicht und schnell. Ich habe viele Web-Applikationen geschrieben, die keinen Verbindungspool für MySQL verwenden.

Dies ist eine Komplikation, auf die Sie verzichten können, solange kein politisches Hindernis zu überwinden ist.

22
mbac32768

Wickeln Sie Ihre Verbindungsklasse ein.

Legen Sie ein Limit für die Anzahl der Verbindungen fest, die Sie herstellen. Geben Sie eine ungenutzte Verbindung zurück. Schließen Sie die Verbindung ab, um die Verbindung zu trennen.

Update: Ich habe etwas in dbpool.py eingefügt:

import sqlalchemy.pool as pool
import MySQLdb as mysql
mysql = pool.manage(mysql)
16
Chris

Alter Thread, aber für allgemeines Pooling (Verbindungen oder andere teure Objekte) verwende ich Folgendes:

def pool(ctor, limit=None):
    local_pool = multiprocessing.Queue()
    n = multiprocesing.Value('i', 0)
    @contextlib.contextmanager
    def pooled(ctor=ctor, lpool=local_pool, n=n):
        # block iff at limit
        try: i = lpool.get(limit and n.value >= limit)
        except multiprocessing.queues.Empty:
            n.value += 1
            i = ctor()
        yield i
        lpool.put(i)
    return pooled

Welche Konstrukte träge sind, hat ein optionales Limit und sollte auf jeden Anwendungsfall verallgemeinern, den ich mir vorstellen kann. Dies setzt natürlich voraus, dass Sie wirklich das Pooling aller Ressourcen benötigen, was Sie für viele moderne SQL-Likes nicht mögen. Verwendungszweck:

# in main:
my_pool = pool(lambda: do_something())
# in thread:
with my_pool() as my_obj:
    my_obj.do_something()

Dies setzt jedoch voraus, dass das von ctor erstellte Objekt bei Bedarf über einen geeigneten Destruktor verfügt (einige Server beenden Verbindungsobjekte nur, wenn sie explizit geschlossen werden).

6
metaperture

Ich habe gerade nach der gleichen Art gesucht.

Ich habe pysqlpool und das sqlalchemy pool module gefunden

2
Willie

Das Erstellen eines eigenen Verbindungspools ist eine schlechte Idee, wenn sich Ihre App jemals für die Verwendung von Multithreading entscheidet. Das Erstellen eines Verbindungspools für eine Anwendung mit mehreren Threads ist viel komplizierter als für eine Anwendung mit einem einzigen Thread. Sie können in diesem Fall etwas wie PySQLPool verwenden.

Es ist auch eine schlechte Idee, einen ORM zu verwenden, wenn Sie nach Leistung suchen.

Wenn Sie mit riesigen/schweren Datenbanken zu tun haben, die viele Selects, Inserts, Aktualisierungen und Löschvorgänge gleichzeitig behandeln müssen, benötigen Sie Leistung, was bedeutet, dass Sie benutzerdefiniert sind SQL geschrieben, um Lookups und Sperrzeiten zu optimieren. Mit einem ORM haben Sie normalerweise nicht diese Flexibilität.

Im Grunde können Sie ja Ihren eigenen Verbindungspool erstellen und ORMs verwenden, aber nur wenn Sie sicher sind, dass Sie nichts von dem benötigen, was ich gerade beschrieben habe.

2
flexo

Als Antwort auf einen alten Thread, aber als ich das letzte Mal überprüft habe, bietet MySQL das Verbindungs-Pooling als Teil seiner Treiber an.

Sie können sie unter:

https://dev.mysql.com/doc/connector-python/de/connector-python-connection-pooling.html

Angenommen, Sie möchten einen Verbindungspool explizit öffnen (wie OP angegeben hatte):

dbconfig = {  "database": "test", "user":"joe" }
cnxpool = mysql.connector.pooling.MySQLConnectionPool(pool_name = "mypool",pool_size = 3, **dbconfig)

Auf diesen Pool wird dann durch Anforderung der Funktion get_connection () aus dem Pool zugegriffen.

cnx1 = cnxpool.get_connection()
cnx2 = cnxpool.get_connection()
1
kilokahn

Verwenden Sie DBUtils, einfach und zuverlässig.

pip install DBUtils

0
ospider