Python-asyncio - 使用 timers/threading 终止异步

Python-asyncio - using timers/threading to terminate async

我有一个异步协程,我想使用 timer/thread 终止它。协程基于 aiortc 的 this example

args = parse_args()
client = Client(connection, media, args.role)

# run event loop
loop = asyncio.get_event_loop()

try:
    timer = None
    if args.timeout:
        print("Timer started")
        timer = threading.Timer(args.timeout, loop.run_until_complete, args=(client.close(),))
        timer.start()

    loop.run_until_complete(client.run())

    if timer:
        timer.join()
except KeyboardInterrupt:
    pass
finally:
    # cleanup
    loop.run_until_complete(client.close())

这不起作用并引发 RuntimeError('This event loop is already running')

为什么会引发错误?我的猜测是因为循环是 运行 在不同的线程上。但是,创建新循环不起作用,因为它将未来附加到不同的循环。

def timer_callback():
    new_loop = asyncio.new_event_loop()
    new_loop.run_until_complete(client.close())

接下来,如何使用计时器结束脚本?

这不是我正在寻找的通用解决方案,我向客户端构造函数添加了一个 timeout 变量,并在 client.run() 中添加了 asyncio.sleep(timeout) 这将退出环形。这对我来说已经足够了。

Following that, how can I use a timer to end the script?

您可以调用 asyncio.run_coroutine_threadsafe() 将协程提交给另一个线程中的事件循环 运行:

    if args.timeout:
        print("Timer started")
        timer = threading.Timer(
            args.timeout,
            asyncio.run_coroutine_threadsafe,
            args=(client.close(), loop),
        )
        timer.start()

但是请注意,由于您使用的是 asyncio,因此您不需要计时器的专用线程,您可以创建一个协程并告诉它在执行某些操作之前等待:

    if args.timeout:
        print("Timer started")
        async def close_after_timeout(): 
            await asyncio.sleep(args.timeout)
            await client.close()
        loop.create_task(close_after_timeout())