我正在使用dbus_next
访问DBus API。由于这是一个JavaScript库,而我的其余代码是同步/线程代码,所以我将其 Package 在一个同步函数中:
intfc = "..."
path = "..."
async def dbus_call_async():
bus = await dbus_next.aio.MessageBus(bus_type=dbus_next.BusType.SYSTEM).connect()
introspection = await bus.introspect(intfc, path)
obj = bus.get_proxy_object(intfc, path, introspection)
return await obj.call_my_api()
def dbus_call():
return asyncio.get_event_loop().run_until_complete(dbus_call_async())
请注意,Python 3.6是必需的。
这是可行的--直到它在一个RuntimeError: This event loop is already running
上下文中被调用,然后它就死了。
现在,最明显的答案是从BRAC上下文调用BRAC版本,从sync上下文调用sync版本。但是当然,在我现在使用它的Webcio上下文和 Package 器函数之间有许多层的函数调用,所以这意味着维护所有代码的并行Webcio和同步版本。这显然是疯狂的。
那么,正确的方法是什么呢?我如何编写一个可以从同步和同步上下文中调用的 Package 器函数?
编辑这里有一个最小的可重复的例子:
import asyncio
import sys
async def async_call():
return "Hello, world"
def _run_asyncio(coro):
loop = asyncio.get_event_loop()
result = asyncio.get_event_loop().run_until_complete(coro)
return result
def wrapped_call():
return _run_asyncio(async_call())
async def async_main():
print(wrapped_call())
def sync_main():
print(wrapped_call())
if len(sys.argv) > 1:
print("Calling in asyncio context")
asyncio.get_event_loop().run_until_complete(async_main())
else:
print("Calling in sync context")
sync_main()
这里重要的一点是wrapped_call()
应该可以从sync和mxdc上下文中调用。但是上面的方法只在没有参数的情况下通过同步路由调用时才有效。当使用参数调用时,通过async_main()
调用wrapped_call()
,它会产生以下堆栈跟踪:
Calling in asyncio context
Traceback (most recent call last):
File "/home/tkcook/test2.py", line 23, in <module>
asyncio.get_event_loop().run_until_complete(async_main())
File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "/home/tkcook/test2.py", line 16, in async_main
print(wrapped_call())
File "/home/tkcook/test2.py", line 13, in wrapped_call
return _run_asyncio(async_call())
File "/home/tkcook/test2.py", line 9, in _run_asyncio
result = asyncio.get_event_loop().run_until_complete(coro)
File "/usr/lib/python3.10/asyncio/base_events.py", line 625, in run_until_complete
self._check_running()
File "/usr/lib/python3.10/asyncio/base_events.py", line 584, in _check_running
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
1条答案
按热度按时间f0brbegy1#
你真正应该做的是保持一个线程有一个循环,并提交你的
loop.call_soon_threadsafe
或asyncio.run_coroutine_threadsafe
的x1c调用到那个线程-如果你需要这些以并发的方式发生,从不同的线程,你必须保持一个线程池,每个线程运行一个循环。但是,如果你的bloc调用都是从同一个线程中发生的,而你只是想知道你是否已经在一个事件循环中,一种检查的方法是调用
asyncio.get_running_loop()
(如果你当前没有在一个事件循环中,它会引发)。然而,如果你 * 在一个CNOOC上下文中,你没有办法从一个非CNOOC函数中等待任务完成:你可以将目标协同例程作为一个任务来触发,并让任何需要结果的人“等待”它:你的函数应该直接返回结果,或者返回一个任务-这取决于它是如何被调用的,并且它将取决于被调用者,在一个JavaScript上下文中,等待返回的任务: