2017-02-22 2 views
0

Ich habe einen Web-Scraper mit Scrapy, die auf Twisted mit Deferreds aufgebaut ist. Für jede Seite, die ich scrapped, möchte ich in mehrere verschiedene Tabellen in einer PostgreSQL-Datenbank einfügen. Ich möchte, dass diese Einfügung nicht blockierend ist. Gibt es eine Möglichkeit, nicht-blockierende Postgres-Interaktion mit einem ORM wie SQLAlchemy zu bekommen?Nonblocking PostgreSQL ORM

Ich verstehe, dass es nicht blockierende Postgres-Interaktion mit alchimia oder txpostgres gibt, aber keiner bietet ORM-Funktionalität. Wenn die Antwort nicht möglich ist, verwende ich eine davon. Wird einer von ihnen dem anderen vorgezogen?

Antwort

1

Die Art und Weise, in der ein ORM in Python erstellt wird, ist im Allgemeinen für asynchronen Betrieb nicht zugänglich.

Eine Haupteigenschaft von Python-ORMs, die attraktiv zu sein scheint, ist offenbar der normale Attributzugriff zum Abrufen und Festlegen von Werten. Beide Probleme bereiten jedoch Probleme.

Für Attributzugriff, um asynchron zu arbeiten, ist das offensichtliche Verhalten für so etwas wie database_object.some_field zu einem Deferred auszuwerten. Dann würde die Anwendung darauf warten, um den tatsächlichen Wert zu erhalten. Der Code endet etwa wie folgt:

d = database_object.some_field 
def got_some_field(result): 
    print("DB obj some_field = {}".format(result)) 
d.addCallback(got_some_field) 

Anstelle eines einfachen Ausdrucks haben Sie vier Zeilen Code. Man könnte argumentieren, dass dies den Wert, den das ORM bieten soll, völlig zerstört hat. Es kann möglich sein, dieses Problem zu umgehen, indem Sie Werte aus der Datenbank laden. Es ist jedoch nicht immer wünschenswert, alles vorab zu laden (es kann die Leistung beeinträchtigen), und es ist nicht immer offensichtlich, dass es korrekt ist (wenn Sie eine Transaktion starten, einige Werte vorab laden, dann einen Vorgang ausführen, der diese Werte ändern könnte) Abrufen sie aus dem Python-Objekt, was soll passieren?).

Aktualisierung der Werte ist noch schlimmer. Während ein synchrones ORM Sie möglicherweise lassen würde:

database_object.some_field = 3 

Wie würde ein asynchrones ORM für etwas Ähnliches arbeiten? Die Zuweisung kann keinen Wert erzeugen. Sie brauchen also ein anderes unbequemes Muster, um Updates korrekt durchführen zu können. Etwas wie:

d = database_object.update("some_field", 3) 
def updated(ignored): 
    # Continue ... 
d.addCallback(updated) 

oder ein sehr kompliziertes System dies in einer Art und Weise hinter den Kulissen zu tun, die nicht für die Inkonsistenz zwischen den Werten in der Datenbank und Werte im Speicher in Python erlaubt. Es ist wahrscheinlich nicht unmöglich, aber der Grad der Komplexität ist vielleicht der Grund, warum niemand das Problem anzugehen scheint.

+0

Danke; das ist sehr interessant. [Dieses 'Twistar'-Tutorial] (http://findingscience.com/twistar/) scheint nahe zu legen, dass sie einen Ansatz für dieses Problem entwickelt haben. Wie passt das in den Rahmen, den Sie angelegt haben? – Hatshepsut

+0

Ich denke, Twistar ist ein wenig niedriger als ein ORM - es ist eine "Active Record Pattern" Implementierung, die für _building_ ein ORM nützlich ist, aber es fehlt viel von dem, was die meisten Menschen Teil eines ORM betrachten würden. Zum Beispiel haben Sie keinen Zugriff auf Attributzugriff basierend auf Daten - Sie haben stattdessen Methoden zum Abrufen und Festlegen sowie eine explizite (Einzelobjekt) "Speichern" -Methode. Und es akzeptiert die Vorstellung, dass die Python-Objekte und die Datenbank für einige Zeit inkonsistent sein werden (bis Sie die Änderungen speichern). Daher müssen Apps darauf achten, nicht von Abfrageergebnissen überrascht zu werden, die nicht von "Speichern" d Änderungen abweichen. –

+0

(Aber nehmen Sie das mit einem Körnchen Salz - mein letzter echter Blick auf Twistar war wahrscheinlich ein halbes Dutzend Jahre alt). –