python-3.x - 使用 Python asyncio 运行并等待来自同步函数的异步函数
问题描述
在我的代码中,我有一个带有属性的类,偶尔需要运行异步代码。有时我需要从异步函数访问属性,有时从同步访问 - 这就是为什么我不希望我的属性是异步的。此外,我的印象是异步属性通常是代码异味。如我错了请纠正我。
我从同步属性执行异步方法并阻止进一步执行直到异步方法完成时遇到问题。
这是一个示例代码:
import asyncio
async def main():
print('entering main')
synchronous_property()
print('exiting main')
def synchronous_property():
print('entering synchronous_property')
loop = asyncio.get_event_loop()
try:
# this will raise an exception, so I catch it and ignore
loop.run_until_complete(asynchronous())
except RuntimeError:
pass
print('exiting synchronous_property')
async def asynchronous():
print('entering asynchronous')
print('exiting asynchronous')
asyncio.run(main())
它的输出:
entering main
entering synchronous_property
exiting synchronous_property
exiting main
entering asynchronous
exiting asynchronous
首先,RuntimeError
捕获似乎是错误的,但如果我不这样做,我会得到RuntimeError: This event loop is already running
异常。
其次,asynchronous()
函数在同步完成后最后执行。我想通过异步方法对数据集进行一些处理,所以我需要等待它完成。如果我await asyncio.sleep(0)
在调用之后添加synchronous_property()
,它会在完成asynchronous()
之前调用main()
,但这对我没有帮助。我需要在完成asynchronous()
之前运行synchronous_property()
。
我错过了什么?我正在运行 python 3.7。
解决方案
Asyncio 在设计上确实坚持不允许嵌套循环。但是,您始终可以在不同的线程中运行另一个事件循环。这是一个变体,它使用线程池来避免每次都必须创建一个新线程:
import asyncio, concurrent.futures
async def main():
print('entering main')
synchronous_property()
print('exiting main')
pool = concurrent.futures.ThreadPoolExecutor()
def synchronous_property():
print('entering synchronous_property')
result = pool.submit(asyncio.run, asynchronous()).result()
print('exiting synchronous_property', result)
async def asynchronous():
print('entering asynchronous')
await asyncio.sleep(1)
print('exiting asynchronous')
return 42
asyncio.run(main())
这段代码在每个同步->异步边界上创建了一个新的事件循环,所以如果你经常这样做,不要期望高性能。可以通过使用每个线程只创建一个事件循环asyncio.new_event_loop
并将其缓存在线程局部变量中来改进它。
推荐阅读
- ruby-on-rails - rails中没有路由匹配?自定义rails中控制器的操作权限
- android - 片段从另一个具有属性初始化的片段继承
- c# - C#正则表达式查找捕获组的数量
- python - Python:为每个函数分配多个返回值?
- javascript - javascript - 使用 xmlhttpRequest 发布大数据
- c - 差异 b/w 使用 %p 和 %d 获取变量地址
- java - mouseMoved(MouseEvent e) 跟不上程序逻辑
- debian - 从 eMMC 卡闪烁到板载 eMMC 的 Beaglebone 问题
- django - 使用 django-crispy-forms 无法显示底部
- python-3.x - 如何获取数组中所有最大值的索引