How can I have a synchronous facade over asyncpg APIs with Python asyncio?(如何使用Python Asyncio在异步pgAPI上实现同步外观?)
问题描述
设想一个异步aiohttp
Web应用程序,该应用程序由通过asyncpg
连接的PostgreSQL数据库支持,并且没有其他I/O。如何才能有一个托管应用程序逻辑的中间层,即而不是异步?(我知道我可以简单地使所有东西都异步--但是想象一下我的应用程序有大量的应用程序逻辑,仅由数据库I/O绑定,并且我不能触及它的所有内容)。
伪码:
async def handler(request):
# call into layers over layers of application code, that simply emits SQL
...
def application_logic():
...
# This doesn't work, obviously, as await is a syntax
# error inside synchronous code.
data = await asyncpg_conn.execute("SQL")
...
# What I want is this:
data = asyncpg_facade.execute("SQL")
...
如何在asyncpg
上构建允许应用程序逻辑进行数据库调用的同步外观?在这种情况下,使用async.run()
或asyncio.run_coroutine_threadsafe()
等浮动的食谱不起作用,因为我们来自一个已经异步的上下文。我假设这不是不可能的,因为原则上已经有一个事件循环可以运行asyncpg
协程。
额外问题:使await
内部同步成为语法错误的设计原理是什么?允许await
来自任何源自协程的上下文不是很有用吗?这样我们就有了在功能构建块中分解应用程序的简单方法?
编辑额外的好处:除了Paul's very good answer之外,我对避免阻塞主线程的解决方案感兴趣(产生更多类似gevent的东西)。另请参阅我对保罗回答的评论.
推荐答案
您需要创建在其中运行异步代码的辅助线程。您可以使用其自己的事件循环来初始化辅助线程,该事件循环将永远运行。通过调用run_coroutine_ThreadSafe()并对返回的对象调用result()来执行每个异步函数。这是concurrent.futures.Future的一个实例,它的result()方法直到协程的结果从第二个线程准备好之后才返回。
这样,您的主线程实际上就像调用同步函数一样调用每个异步函数。在每个函数调用完成之前,主线程不会继续。顺便说一下,同步函数是否在事件循环上下文中实际运行并不重要。对result()的调用当然会挡路主线程的事件循环。如果您想要获得从同步代码运行异步函数的效果,这是无法避免的。
不用说,这是一件难看的事情,而且它暗示了错误的程序结构。但您正在尝试转换旧版程序,这可能会对此有所帮助。import asyncio
import threading
from datetime import datetime
def main():
def thr(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
loop = asyncio.new_event_loop()
t = threading.Thread(target=thr, args=(loop, ), daemon=True)
t.start()
print("Hello", datetime.now())
t1 = asyncio.run_coroutine_threadsafe(f1(1.0), loop).result()
t2 = asyncio.run_coroutine_threadsafe(f1(2.0), loop).result()
print(t1, t2)
if __name__ == "__main__":
main()
>>> Hello 2021-10-26 20:37:00.454577
>>> Hello 1.0 2021-10-26 20:37:01.464127
>>> Hello 2.0 2021-10-26 20:37:03.468691
>>> 1.0 2.0
这篇关于如何使用Python Asyncio在异步pgAPI上实现同步外观?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何使用Python Asyncio在异步pgAPI上实现同步外观?


- python check_output 失败,退出状态为 1,但 Popen 适用于相同的命令 2022-01-01
- 如何在 python3 中将 OrderedDict 转换为常规字典 2022-01-01
- 使用Heroku上托管的Selenium登录Instagram时,找不到元素';用户名'; 2022-01-01
- 分析异常:路径不存在:dbfs:/databricks/python/lib/python3.7/site-packages/sampleFolder/data; 2022-01-01
- 如何在 Python 的元组列表中对每个元组中的第一个值求和? 2022-01-01
- python-m http.server 443--使用SSL? 2022-01-01
- padding='same' 转换为 PyTorch padding=# 2022-01-01
- 沿轴计算直方图 2022-01-01
- 如何将一个类的函数分成多个文件? 2022-01-01
- pytorch 中的自适应池是如何工作的? 2022-07-12