Python async: Waiting for stdin input while doing other stuff

一个人想着一个人 提交于 2021-02-05 06:40:47

问题


I'm trying to create a WebSocket command line client that waits for messages from a WebSocket server but waits for user input at the same time.

Regularly polling multiple online sources every second works fine on the server, (the one running at localhost:6789 in this example), but instead of using Python's normal sleep() method, it uses asyncio.sleep(), which makes sense because sleeping and asynchronously sleeping aren't the same thing, at least not under the hood.

Similarly, waiting for user input and asynchronously waiting for user input aren't the same thing, but I can't figure out how to asynchronously wait for user input in the same way that I can asynchronously wait for an arbitrary amount of seconds, so that the client can deal with incoming messages from the WebSocket server while simultaneously waiting for user input.

The comment below in the else-clause of monitor_cmd() hopefully explains what I'm getting at:

import asyncio
import json
import websockets

async def monitor_ws():
    uri = 'ws://localhost:6789'
    async with websockets.connect(uri) as websocket:
        async for message in websocket:
            print(json.dumps(json.loads(message), indent=2, sort_keys=True))

async def monitor_cmd():
    while True:

        sleep_instead = False

        if sleep_instead:
            await asyncio.sleep(1)
            print('Sleeping works fine.')
        else:
            # Seems like I need the equivalent of:
            # line = await asyncio.input('Is this your line? ')
            line = input('Is this your line? ')
            print(line)
try:
    asyncio.get_event_loop().run_until_complete(asyncio.wait([
        monitor_ws(),
        monitor_cmd()
    ]))
except KeyboardInterrupt:
    quit()

This code just waits for input indefinitely and does nothing else in the meantime, and I understand why. What I don't understand, is how to fix it. :)

Of course, if I'm thinking about this problem in the wrong way, I'd be very happy to learn how to remedy that as well.


回答1:


You can use the aioconsole third-party package to interact with stdin in an asyncio-friendly manner:

line = await aioconsole.ainput('Is this your line? ')



回答2:


Borrowing heavily from aioconsole, if you would rather avoid using an external library you could define your own async input function:

async def ainput(string: str) -> str:
    await asyncio.get_event_loop().run_in_executor(
            None, lambda s=string: sys.stdout.write(s+' '))
    return await asyncio.get_event_loop().run_in_executor(
            None, sys.stdin.readline)


来源:https://stackoverflow.com/questions/58454190/python-async-waiting-for-stdin-input-while-doing-other-stuff

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!