简体   繁体   中英

Python asyncio loop already running when using asyncio.run and trying to add tasks

I am very new to asyncio and I find the EchoServer example very confusing. I am trying to achieve a simple situation where a server accepts multiple clients, runs that in a coroutine and handles data, and a UI thread which handles ncurses input. I currently have the following, which, in code, conveys the idea I think. But it does not work.

import asyncio

async def do_ui():
    await asyncio.sleep(1)
    print('doing')
    await do_ui()

async def run_game():
    loop = asyncio.get_running_loop()

    server = await GameServer.create_server()
    loop.create_task(server.serve_forever())
    loop.create_task(do_ui())

    loop.run_forever()

def run():
    asyncio.run(run_game())

The problem starts in GameServer.create_server, where I, for encapsulation reasons, want to delegate creating the server to. However this is an asynchronous action (for some reason) and so has to be awaited. See the server code below:

class GameServer:

    @staticmethod
    async def create_server():
        loop = asyncio.get_running_loop()
        return await loop.create_server(
                    lambda: GameServerProtocol(),
                    '127.0.0.1', 8888
        )

This forces me to make run_game async aswell and await it in the run method, which is my setup.py entrypoint, so I can't do that. Using the asyncio.run method however starts a different event loop and I am not able to access it anymore.

How do I solve this? And to vent my frustration, how is this in any way easier than just using threads?

You cannot use loop.run_forever() whilst the event loop is already running. For example, the following code will not work:

import asyncio

async def main():
    loop=asyncio.get_running_loop()
    loop.run_forever()

if __name__ == '__main__':
    asyncio.run(main())

But this code will work, and has the "run forever" behaviour you appear to be looking for:

import asyncio

async def do_ui():
    while True:
        await asyncio.sleep(1)
        print('doing ui')

async def main():
    loop = asyncio.get_running_loop()
    loop.create_task(do_ui())
    # insert game server code here


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.create_task(main())
    loop.run_forever()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM