Tornado
のSQLAlchemy
をasync
にする方法は? async mongo exampleのMongoDBの例が見つかりましたが、motor
のようなものは見つけられませんでした。SQLAlchemy
です。誰もがtornado.gen
(私は以下SQLAlchemy
、私のハンドラがデータベースから読み込んで結果を返す瞬間、私はこの非同期にしたいと思います)を使用して実行するSQLAlchemy
クエリを行う方法を知っていますか?TornadoでSQLAlchemyを非同期にするには?
答えて
ORMは、明示的な非同期プログラミング、つまりネットワークアクセスを使用する何らかのものが発生したときに明示的なコールバックを生成する必要がある場合には適しません。これの主な理由は、ORMが明示的な非同期と多かれ少なかれ互換性のあるlazy loadingパターンを広範に使用していることです。このようなコード: - あなたはuser.addresses
を言うとき、行、および次をロードするためにfirst()
を言うとき.addresses
コレクションが既に存在していないという場合には、1
user = Session.query(User).first()
print user.addresses
は、実際には2つの別々のクエリを発行します、または期限切れになっています。本質的に、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回ブロックされます。したがって、非同期エンジンが使用されておらず、コールバックが実際にブロックされていない場合でも、上記のコードを明示的な非同期スタイルで記述すると、上記の外部関数呼び出しは、オーバーヘッドを含まない、少なくとも3つの関数呼び出し明示的な非同期システムまたはDBAPI自身によって呼び出されます。したがって、単純なアプリケーションには、ステートメント実行の単純な抽象化を取り巻く関数呼び出しオーバーヘッドの3倍のペナルティが自動的に与えられます。 Pythonではfunction call overhead is everythingです。
これらの理由から、私は、Webページを配信するようなものはすべて非同期で実行したいと思うほど、明示的な非同期システムを取り巻く誇大宣伝に興奮しています(node.js )。暗黙の非同期システムを使用することをお勧めします。特に、geventは、非同期モデルのすべてのノンブロッキングIOメリットと、明示的コールバックの構造的冗長性/欠点のいずれも取得しません。私はこれらの2つのアプローチのユースケースを理解しようとしています。そのため、すべての問題の解決策として明示的な非同期アプローチが魅力的です。js - 冗長性とコードの複雑さを減らすためにスクリプト言語を使用しています。ウェブページの配信などの単純なものに対する明示的な非同期は、何もしませんが、 IOをブロックすることがそのような問題であっても(多量の大量のWebサイトが同期IOモデルでうまくいく場合) Geventベースのシステムは実績があり、人気が高まっているので、ORMが提供するコード自動化が好きな場合は、geventのようなシステムが提供するasync-IOスケジューリングの自動化を採用することもできます。
更新:Nick Coghlanは、great article on the subject of explicit vs. implicit asyncを指摘しました。これもまた、ここで読む必要があります。また、Nickの記事の主なおかげで、以前に述べたgeventの不利な点を逆にして、pep-3156 now welcomes interoperability with geventという事実に更新されました。だから将来、これらのアプローチを統合するシステムが利用可能になると、データベースロジックのためにgeventを使ってTornadoのハイブリッドを推奨します。
私は、コミュニティ内の他の人々、またはzzzeek、疑問に思います。彼らはORMの風景やトルネード、またはこの回答のレビューを正当な意味で何か重要な変更されていますか?私は潜在的にこの問題に直面しているので私は尋ねています:https://stackoverflow.com/questions/44599402/what-is-a-good-way-to-organize-your-models-connections-if-one-wants- to-use-sqla BokehサーバーアプリケーションはTornadoを使用しており、そこから情報を取得するにはdbに接続する必要があります。 – Thornhale
いつもと同じ答え...ビジネスと永続ロジックにはノンブロッキングIOは必要ありません。すべてを強制的に「明示的非同期」にするWebフレームワークを使用することを余儀なくされた場合、最良の解決策はa)です。フラスコやピラミッドのような通常のウェブフレームワークを使用するか、またはそれを短くします。スレッドプールを使用する – zzzeek
私はこれまで同じ問題を抱えていましたが、信頼できるAsync-MySQLライブラリが見つかりませんでした。しかし、Asyncio + Postgresを使ってクールな解決策があります。あなただけのボックスのうち、SQLAlchemyのサポートが付属していますaiopgライブラリを使用する必要があります。
import asyncio
from aiopg.sa import create_engine
import sqlalchemy as sa
metadata = sa.MetaData()
tbl = sa.Table('tbl', metadata,
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('val', sa.String(255)))
@asyncio.coroutine
def go():
engine = yield from create_engine(user='aiopg',
database='aiopg',
host='127.0.0.1',
password='passwd')
with (yield from engine) as conn:
yield from conn.execute(tbl.insert().values(val='abc'))
res = yield from conn.execute(tbl.select().where(tbl.c.val=='abc'))
for row in res:
print(row.id, row.val)
loop = asyncio.get_event_loop()
loop.run_until_complete(go())
私は次の方法で、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ツールを使用してクエリを構成します。
竜巻はないが、我々GINO projectでasyncioで作られたSQLAlchemyの非同期の並べ替え:それは少しのように見える
import asyncio
from gino import Gino, enable_task_local
from sqlalchemy import Column, Integer, Unicode, cast
db = Gino()
class User(db.Model):
__tablename__ = 'users'
id = Column(Integer(), primary_key=True)
nickname = Column(Unicode(), default='noname')
async def main():
await db.create_pool('postgresql://localhost/gino')
# Create object, `id` is assigned by database
u1 = await User.create(nickname='fantix')
print(u1.id, u1.nickname) # 1 fantix
# Retrieve the same row, as a different object
u2 = await User.get(u1.id)
print(u2.nickname) # fantix
# Update affects only database row and the operating object
await u2.update(nickname='daisy')
print(u2.nickname) # daisy
print(u1.nickname) # fantix
# Returns all user objects with "d" in their nicknames
users = await User.query.where(User.nickname.contains('d')).gino.all()
# Find one user object, None if not found
user = await User.query.where(User.nickname == 'daisy').gino.first()
# Execute complex statement and return command status
status = await User.update.values(
nickname='No.' + cast(User.id, Unicode),
).where(
User.id > 10,
).gino.status()
# Iterate over the results of a large query in a transaction as required
async with db.transaction():
async for u in User.query.order_by(User.id).gino.iterate():
print(u.id, u.nickname)
loop = asyncio.get_event_loop()
enable_task_local(loop)
loop.run_until_complete(main())
が、SQLAlchemyのORMより実際全く異なります。 SQLAlchemyコアの一部のみを使用し、その上に簡単なORMを作成したためです。その下にはasyncpgが使用されているので、PostgreSQLの場合はのみです。
更新:GINOは現在、Vladimir Goncharovの貢献により、トルネードをサポートしています。この回答の投稿から4年が経過しています。docs here
- 1. Tornadoでの非同期バックグラウンドタスクの実行
- 2. Tornadoとの非同期TCPClientとTCPServer
- 3. 非同期サブルーチンの作成中にPython tornadoのrun_syncを使用するには?
- 4. 非同期Tornadoコードを最適化します。スレッドロックを最小限にする
- 5. nodejsで非同期に同期する
- 6. 非同期キューモニタリングのためのPornでのTornadoの使用
- 7. Tornadoで余分な非同期メソッドを呼び出す方法は?
- 8. Python Tornado:これを非同期にするにはどうすればよいですか?
- 9. Meteor.methodsを同期非同期にする
- 10. コアデータのManagedObjectContext.ExecuteFetchRequestを非同期で非同期にする方法
- 11. ダーツの非同期は本当に非同期ですか?
- 12. TornadoとRedisを非同期で使用するにはどうすればよいですか?
- 13. 「非同期キーワード非同期」関数を「非同期キーワード非同期」関数に変換できますか?
- 14. 関数へのTornado非同期呼び出し
- 15. JavaScript:同期コードで非同期FileReaderを使用するには?
- 16. 非同期メソッド非同期に新
- 17. 春非同期 - 非同期豆に
- 18. メソッドを非同期にするには?
- 19. RxJavaで非同期メソッドを同期する方法は? RxJavaの非同期ウォーターフォール
- 20. BitmapFrameを非同期で非同期メソッドで作成する
- 21. 非同期に非同期デリゲートを呼び出しますか?
- 22. 同期と非同期AJAXを同時に実行する
- 23. TornadoでRedis接続を処理する適切な方法は何ですか? (非同期 - パブ/サブ)
- 24. ウェブページは非同期に
- 25. Asp MVC非同期コントローラアクションは自動的に非同期ですか?
- 26. 非同期 - 彼らは私がノードと非同期に新しいです
- 27. 同期フラスコ非同期を作る - 人々は「非同期」または「フラスコの非同期を作る」について話すときフラスコのインスタンスが
- 28. 非同期メソッドを同期する
- 29. 非同期通信を同期する
- 30. 非同期に非同期にPython呼び出しリモートオブジェクトメソッド
チェックアウト:http://pylover.dobisel.com/posts/aiopg-aiopg_sa-and-aiopg8000/ – pylover