异步IO在Windows上无法读取标准输入

14

我试图在Windows 7 64位和Python 3.4.3上异步读取stdin。

我尝试了一个受SO答案启发的方法:

import asyncio
import sys


def reader():
    print('Received:', sys.stdin.readline())


loop = asyncio.get_event_loop()
task = loop.add_reader(sys.stdin.fileno(), reader)
loop.run_forever()
loop.close()

然而,它会引发一个OSError: [WInError 100381] An operation was attempted on something that is not a socket

stdin这样的类似文件对象是否可以被包装在一个类中,使其具有套接字的API?我已经单独提出了这个问题,但如果解决方案很简单,请在此回答。

假设我不能将文件对象包装成套接字,那么我尝试使用流,受到这个代码片段的启发:

import asyncio
import sys


@asyncio.coroutine
def stdio(loop):
    reader = asyncio.StreamReader(loop=loop)
    reader_protocol = asyncio.StreamReaderProtocol(reader)
    yield from loop.connect_read_pipe(lambda: reader_protocol, sys.stdin)


@asyncio.coroutine
def async_input(loop):
    reader = yield from stdio(loop)
    line = yield from reader.readline()
    return line.decode().replace('\r', '').replace('\n', '')


@asyncio.coroutine
def main(loop):
    name = yield from async_input(loop)
    print('Hello ', name)


loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()

这会在asyncio.base_events._make_read_pipe_transport引发一个NotImplementedError

请指导如何在Windows上使用asyncio读取stdin...

1个回答

19
NotImplementedError异常被引发,因为在asyncio中默认的事件循环SelectorEventLoop不支持连接管道协程。您需要使用ProactorEventLoop来支持Windows上的管道。但是,它仍然无法正常工作,因为显然connect_read_pipeconnect_write_pipe函数不支持Python 3.5.1中的stdin/stdout/stderr或文件。
一种异步读取stdin的方法是使用线程和循环的run_in_executor方法。下面是一个简单的示例供参考:
import asyncio
import sys

async def aio_readline(loop):
    while True:
        line = await loop.run_in_executor(None, sys.stdin.readline)
        print('Got line:', line, end='')

loop = asyncio.get_event_loop()
loop.run_until_complete(aio_readline(loop))
loop.close()
在这个例子中,函数 sys.stdin.readline()loop.run_in_executor 方法在另一个线程中调用。该线程将一直阻塞,直到 stdin 接收到换行符,与此同时,如果有其他协程存在,循环就可以自由地执行它们。

嗯,但这似乎是阻塞的,对吧?有没有办法让它变成非阻塞的? - omni
2
@masi aio_readline() 是非阻塞的,程序本身通过使用run_until_compete()来实现阻塞。但是你应该只在你的应用程序中使用await loop.run_in_executor(None, sys.stdin.readline)部分。其余部分只是为了示范用法。 - Gabriel Cangussu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接