60

どうやって作るSQLAlchemyの?async mongo exampleで MongoDB の例を見つけましたが、 for のようなものは見つかりませんでした。実行するクエリを作成する方法を知っている人はいますか(私は以下を使用しています。現在、ハンドラーはデータベースから読み取り、結果を返します。これを非同期にしたいと思います)。TornadoasyncmotorSQLAlchemySQLAlchemytornado.genMySQLSQLAlchemy

4

6 に答える 6

87

ORM は、明示的な非同期プログラミング、つまり、ネットワーク アクセスを使用する何かが発生するたびにプログラマが明示的なコールバックを生成する必要がある場合にはあまり適していません。この主な理由は、ORM が遅延読み込みパターンを多用しているためです。これは、明示的な非同期と多かれ少なかれ互換性がありません。次のようなコード:

user = Session.query(User).first()
print user.addresses

は、実際には 2 つの別個のクエリを発行します。1 つは行first()をロードすると言ったとき、もう 1 つuser.addressesは、.addressesコレクションがまだ存在しない場合、または期限切れになっている場合に と言うときです。基本的に、ORM コンストラクトを処理するほぼすべてのコード行が IO でブロックされる可能性があるため、数秒で大規模なコールバック スパゲッティになります。さらに悪いことに、これらのコード行の大部分は実際には IO でブロックされません。そのため、単純な属性アクセス操作でコールバックを接続するすべてのオーバーヘッドにより、プログラムの効率も大幅に低下します。

明示的な非同期モデルの主な問題は、複雑なシステムに膨大な Python 関数呼び出しのオーバーヘッドを追加することです。これは、遅延読み込みで発生するようなユーザーに面する側だけでなく、システムがどのように抽象化を提供するかに関して内部側でも発生します。 Python データベース API (DBAPI)。SQLAlchemy が基本的な非同期サポートを持っていても、非同期パターンを使用しない大多数のプログラムや、同時実行性が高くない非同期プログラムでさえ、重大なパフォーマンス ペナルティを課すことになります。SQLAlchemy、またはその他の ORM または抽象化レイヤーには、次のようなコードがあると考えてください。

def execute(connection, statement):
     cursor = connection.cursor()
     cursor.execute(statement)
     results = cursor.fetchall()
     cursor.close()
     return results

上記のコードは、接続に対して SQL ステートメントを実行するという単純な操作のように見えます。しかし、psycopg2 の非同期拡張のような完全に非同期の DBAPI を使用すると、上記のコードは IO で少なくとも 3 回ブロックされます。したがって、非同期エンジンが使用されておらず、コールバックが実際にブロックされていない場合でも、上記のコードを明示的な非同期スタイルで記述することは、上記の外部関数呼び出しが、1 つではなく、少なくとも 3 つの関数呼び出しになることを意味します。これには、課されるオーバーヘッドは含まれません。明示的な非同期システムまたは DBAPI 呼び出し自体によって。したがって、単純なアプリケーションには、ステートメント実行に関する単純な抽象化に関連する関数呼び出しのオーバーヘッドの 3 倍のペナルティが自動的に与えられます。Python では、関数呼び出しのオーバーヘッドがすべてです。

これらの理由から、明示的な非同期システムをめぐる誇大広告については、少なくとも、Web ページの配信 (node.js を参照) のように、すべてをすべて非同期にしたいと考える人がいるほどではありません。代わりに暗黙の非同期システムを使用することをお勧めします。最も顕著なのはgevent ですここでは、非同期モデルのノンブロッキング IO の利点をすべて享受でき、明示的なコールバックの構造的な冗長性や欠点はありません。私は引き続きこれら 2 つのアプローチの使用例を理解しようとしていますが、すべての問題の解決策としての明示的な非同期アプローチの魅力に当惑しています。つまり、node.js で見られるように、私たちはスクリプト言語を冗長性とコードの複雑さを削減するための最初の場所であり、Web ページの配信などの単純なことに対する明示的な非同期は、gevent などによって自動化できるボイラープレートを追加する以外に何もしないようです。そのような場合 (大量の Web サイトの多くは、同期 IO モデルで問題ありません)。Gevent ベースのシステムは生産実績があり、その人気は高まっています。したがって、ORM が提供するコードの自動化が気に入った場合は、

更新: Nick Coghlan は、明示的非同期と暗黙的非同期の主題に関する彼の素晴らしい記事を指摘しました。これもここで読む必要があります。また、 pep-3156 が gevent との相互運用性を歓迎するようになったという事実も更新されました。これは、前に述べた gevent への無関心を逆転させます。主に Nick の記事のおかげです。したがって、将来、これらのアプローチを統合するシステムが利用可能になったら、データベース ロジックに gevent を使用する Tornado のハイブリッドをお勧めします。

于 2013-05-12T00:44:41.280 に答える
4

次の方法で sqlalchemy でトルネードを使用しています。


from tornado_mysql import pools
from sqlalchemy.sql import table, column, select, join
from sqlalchemy.dialects import postgresql, mysql

# from models import M, M2

t = table(...)
t2 = table(...)

xxx_id = 10

j = join(t, t2, t.c.t_id == t2.c.id)
s = select([t]).select_from(j).where(t.c.xxx == xxx_id)

sql_str = s.compile(dialect=mysql.dialect(),compile_kwargs={"literal_binds": True})


pool = pools.Pool(conn_data...)
cur = yield pool.execute(sql_str)
data = cur.fetchone()

その場合、sqlalchemy モデルと sqlalchemy ツールを使用してクエリを作成できます。

于 2016-05-18T14:32:13.127 に答える
1

SQLAlchemy 1.4 は asyncio をネイティブにサポートしています (現在はベータ版):

https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html

于 2021-02-17T20:07:02.113 に答える