python - 如何覆盖同步函数以运行异步代码
问题描述
我正在寻找定义一个新的连接,如下所示:https ://udsoncan.readthedocs.io/en/latest/udsoncan/connection.html#defining-a-new-connection
但是,我想从那里调用异步代码(即使发送/等待异步)。我似乎无法让它工作。
考虑以下示例作为我要实现的目标:
import asyncio
async def some_task():
await asyncio.sleep(1) # Async task
print("Done")
def sync_method():
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.sleep(5)) # Some async event
print("sure")
async def main():
sync_method()
await asyncio.gather(some_task(), some_task(), some_task())
if __name__ == "__main__":
asyncio.run(main())
但这会引发错误(从未等待睡眠;但如果我等待它,则会收到从非异步函数调用的等待错误)。但我读到(见这里)这是如何从同步函数调用异步函数。
所以,基本上我的代码是异步的,并且main
在事件循环中运行。现在,我想调用同步函数,但本质上是想通过使用异步方法使其成为非阻塞的。
我究竟做错了什么?
编辑 - 按要求回溯...
Traceback (most recent call last):
File ".\tmp_sync_async.py", line 18, in <module>
asyncio.run(main())
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1520.0_x64__qbz5n2kfra8p0\lib\asyncio\runners.py", line 43, in run
return loop.run_until_complete(main)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1520.0_x64__qbz5n2kfra8p0\lib\asyncio\base_events.py", line 616, in run_until_complete
return future.result()
File ".\tmp_sync_async.py", line 13, in main
sync_method()
File ".\tmp_sync_async.py", line 9, in sync_method
loop.run_until_complete(asyncio.sleep(3))
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1520.0_x64__qbz5n2kfra8p0\lib\asyncio\base_events.py", line 592, in run_until_complete
self._check_running()
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.1520.0_x64__qbz5n2kfra8p0\lib\asyncio\base_events.py", line 552, in _check_running
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
sys:1: RuntimeWarning: coroutine 'sleep' was never awaited
更新:根据我的发现,run_until_complete
如果从同步代码开始然后尝试运行异步代码(即,如果main()
在我的情况下是同步代码),则方法很好。
解决方案
您可以使用生成器返回协程:
import asyncio
async def some_task():
await asyncio.sleep(1) # Async task
print("Done")
def sync_method():
# A yield statement converts a function into a generator
# The yield statement effectively freezes the function and no code below a yield is executed until the next item is requested. The earlier asyncio implementations were actually done using yield statements.
yield asyncio.sleep(5) # Some async event
print("sure")
async def run_promises(future_generator):
# Fetch the items from the generator one by one
for future in future_generator:
# Wait for the future result, the next yield is not requested until this is done
await future
async def main():
# To run in the background:
asyncio.create_task(run_promises(sync_method()))
# To wait:
await run_promises(sync_method())
await asyncio.gather(some_task(), some_task(), some_task())
if __name__ == "__main__":
asyncio.run(main())
推荐阅读
- c++ - AES128 和 AES256 在密钥扩展和字节生成方面有什么区别?(也许是 AES192)
- java - 使用流将一组字符串划分为大小为 x 的子集
- linux - 如何使用 bash 脚本从 csv 文件中读取特定整数?
- odbc - 如何将 LabVIEW 连接到 MySQL MariaDB
- javascript - 如何检查firestore文档是否具有特定字段
- ios - 如何将 JSON 转换为字符串(\"key\" : value)格式
- sql-server - 在没有任何聚合函数的情况下使用 PIVOT
- r - 将 R 函数多次应用于一个数据集,但每次更改一个参数的值
- c# - 由于此错误,我的代码行无法工作?
- node.js - 数据未发送到 plotly