2015-07-20 18 views
11

Sto cercando di leggere in modo asincrono stdin su Windows 7 a 64-bit e Python 3.4.3aysncio non può leggere stdin su Windows

Ho provato questo ispirato da un SO answer:

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() 

Tuttavia, solleva un OSError: [WInError 100381] An operation was attempted on something that is not a socket.

Un oggetto simile a un file come stdin può essere incluso in una classe per assegnargli l'API di un socket? Ho asked this question separately, ma se la soluzione è semplice, per favore rispondi qui.

Supponendo che non posso avvolgere un oggetto simile a file per renderlo un socket, ho provato ad utilizzare i flussi come ispirato da this gist:

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() 

E questo solleva un NotImplementedError in asyncio.base_events._make_read_pipe_transport

Si prega di consigliare come leggere stdin utilizzando asyncio su Windows ...

risposta

10

L'eccezione NotImplementedError viene sollevata perché lo connect pipes coroutines non è su sponsorizzato da SelectorEventLoop, che è il ciclo di eventi predefinito impostato su asyncio. È necessario utilizzare un ProactorEventLoop per supportare le pipe su Windows. Tuttavia, non funzionerebbe ancora perché apparentemente le funzioni connect_read_pipe e connect_write_pipe non supportano stdin/stdout/stderr o file in Windows come Python 3.5.1.

Un modo per leggere da stdin con un comportamento asincrono consiste nell'utilizzare un thread con il metodo run_in_executor del ciclo. Ecco un semplice esempio per riferimento:

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() 

Nell'esempio la funzione sys.stdin.readline() viene chiamata all'interno di un altro filo dal metodo loop.run_in_executor. Il thread rimane bloccato fino a quando stdin riceve un avanzamento riga, nel frattempo il ciclo è libero di eseguire altre coroutine se esistessero.