首页 文章

是否可以只运行asyncio事件循环的一个步骤

提问于
浏览
8

我正在使用asyncio和tkinter开发一个简单的图形网络应用程序 . 我遇到了将asyncio事件循环与Tk的mainloop相结合的问题 . 如果可能的话,我想在没有线程的情况下这样做,因为这两个库(但特别是tkinter)都不是非常线程安全的 . 目前,我在asyncio协程中使用Tk.update,它只运行tk事件循环的一次迭代:

@asyncio.coroutine
def run_tk(tk, interval=0.1):
    try:
        while True:
            tk.update()
            yield from asyncio.sleep(interval)
    except TclError as e:
        if "application has been destroyed" not in e.args[0]:
            raise

但是,为了探索所有选项,我想知道是否可以执行反向 - 如果可以在tk回调中仅调用asyncio事件循环的单次迭代 .

2 回答

  • 10

    loop.run_once() 这样的公共方法缺失是故意的 . 并非每个受支持的事件循环都有一个迭代一步的方法 . 通常,底层API具有创建事件循环并永久运行它的方法,但模拟单个步骤可能非常无效 .

    如果您真的需要它,您可以轻松实现单步迭代:

    import asyncio
    
    
    def run_once(loop):
        loop.call_soon(loop.stop)
        loop.run_forever()
    
    
    loop = asyncio.get_event_loop()
    
    for i in range(100):
        print('Iteration', i)
        run_once(loop)
    
  • 0

    我使用以下过程创建自己的 run_once()run_forever() .

    这是一个简化的例子:

    import asyncio
    
    async def worker(**kwargs):
        oid = kwargs.get('oid', '0.0.0.0.0.0')
        time = kwargs.get('time', 1)
    
        try:
            # Do stuff.
            print('start: ' + oid)
        except Exception as exc:
            print(exc)
        finally:
            await asyncio.sleep(time)
            print('terminate: ' + oid)
    
    async def worker_run_forever(**kwargs):
        while True:
            await worker(**kwargs)
    
    def init_loop(configs, forever=True):
        loop = asyncio.get_event_loop()
    
        if forever:
            futures = [
                asyncio.ensure_future(
                    worker_run_forever(
                        oid=conf['oid'], time=conf['time']
                    )
                ) for conf in configs
            ]
    
        else:
            futures = [
                asyncio.ensure_future(
                    worker(
                        oid=conf['oid'], time=conf['time']
                    )
                ) for conf in configs
            ]
    
        return loop, futures
    
    def run_once(configs):
        print('RUN_ONCE')
        loop, futures = init_loop(configs, forever=False)
        result = loop.run_until_complete(asyncio.gather(*futures))
        print(result)
    
    def run_forever(configs):
        print('RUN_FOREVER')
        loop, _ = init_loop(configs, forever=True)
        try:
            loop.run_forever()
    
        except KeyboardInterrupt:
            pass
    
        finally:
            print("Closing Loop")
            loop.close()
    
    if __name__ == '__main__':
        configurations = [
            {'time': 5, 'oid': '1.3.6.3.2.4'},
            {'time': 6, 'oid': '1.3.6.3.5.5'},
            {'time': 1, 'oid': '1.3.6.3.5.6'},
        ]  # TODO :: DUMMY
    
        run_once(configurations)
        run_forever(configurations)
    

相关问题