2017-02-22 38 views
0

У меня есть скребок с использованием Scrapy, который построен на Twisted с использованием отложенных. Для каждой страницы scraped я хочу вставить в несколько разных таблиц в базе данных PostgreSQL. Я бы хотел, чтобы эта вставка была неблокирующей. Есть ли способ получить неблокирующее взаимодействие Postgres с ORM, например SQLAlchemy?Nonblocking PostgreSQL ORM

Я понимаю, что существует неблокирующее взаимодействие Postgres с alchimia или txpostgres, но не предлагает функциональность ORM. Если ответ невозможен, я воспользуюсь одним из них. Один из них предпочитает другого?

ответ

1

Способ, которым ORM построен в Python, обычно не поддается асинхронной работе.

Первичная функция ORM Python, которая кажется привлекательной, по-видимому, является нормальным доступом к атрибутам для получения и установки значений. Однако обе эти проблемы.

Для доступа к атрибутам для асинхронной работы очевидное поведение для чего-то вроде database_object.some_field для оценки на Deferred. Тогда приложение будет ожидать от этого получения фактического значения. Код в конечном итоге выглядит примерно так:

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

Вместо простого выражения у вас есть четыре строки кода. Можно утверждать, что это полностью разрушило значение, которое ORM предназначено для обеспечения. Это может можно обойти эту проблему путем предварительной загрузки значений из базы данных. Тем не менее, не всегда желательно предварительно загружать все (это может повредить производительность), и не всегда очевидно, что это правильно (если вы начинаете транзакцию, предварительно загружаете некоторые значения, выполняете операцию, которая может изменить эти значения, тогда получить их из объекта Python, что должно произойти?).

Обновление значений еще хуже. В то время как синхронный ОРМ может позволить вам:

database_object.some_field = 3 

Как асинхронный ORM работа что-то подобное? Присвоение не может дать значение вообще. Таким образом, вам нужна еще одна неудобная схема, чтобы иметь возможность делать обновления правильно. Что-то вроде:

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

или очень сложной системы, чтобы сделать это за кулисами так, что не допускает расхождений между значениями в базе данных и значений в памяти в Python. Это, вероятно, не невозможно, но степень сложности может быть связана с тем, почему никто, похоже, не справился с этой проблемой.

+0

Спасибо; это очень интересно. [Этот учебник twistar [http://findingscience.com/twistar/], похоже, предполагает, что они разработали некоторый подход к этой проблеме. Как это вписывается в рамки, которые вы выложили? – Hatshepsut

+0

Я думаю, что twistar немного ниже уровня, чем ORM - это реализация «активной записи», которая полезна для _building_ ORM, но в ней отсутствует много того, что большинство людей рассмотрит как часть ORM. Например, у вас нет доступа к данным на основе доступа к атрибутам - вместо этого вы получаете и устанавливаете методы наряду с явным (однообъектным) методом «сохранения». И он согласен с тем, что объекты Python и база данных будут непоследовательны некоторое время (пока вы не сохраните изменения). Поэтому приложения должны стараться не удивляться результатам запроса, которые не отражают изменения «save» d. –

+0

(Но возьмите это с солью - мой последний реальный взгляд на twistar был, вероятно, полдюжины лет назад). –