[英]python asyncio how to read StdIn and write to StdOut?
I have a need to async read StdIn in order to get messages (json terminated by \\r\\n) and after processing async write updated message to StdOut.我需要异步读取 StdIn 以获取消息(json 由 \\r\\n 终止),并在处理异步后将更新的消息写入 StdOut。
At the moment I am doing it synchronous like:目前我正在同步进行,例如:
class SyncIOStdInOut():
def write(self, payload: str):
sys.stdout.write(payload)
sys.stdout.write('\r\n')
sys.stdout.flush()
def read(self) -> str:
payload=sys.stdin.readline()
return payload
How to do the same but asynchronously?如何执行相同但异步的操作?
Here's an example of echo stdin
to stdout
using asyncio streams (for Unix).这是使用异步流(对于 Unix)将
stdout
stdin
回显到stdout
的示例。
import asyncio
import sys
async def connect_stdin_stdout():
loop = asyncio.get_event_loop()
reader = asyncio.StreamReader()
protocol = asyncio.StreamReaderProtocol(reader)
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
w_transport, w_protocol = await loop.connect_write_pipe(asyncio.streams.FlowControlMixin, sys.stdout)
writer = asyncio.StreamWriter(w_transport, w_protocol, reader, loop)
return reader, writer
async def main():
reader, writer = await connect_stdin_stdout()
while True:
res = await reader.read(100)
if not res:
break
writer.write(res)
if __name__ == "__main__":
asyncio.run(main())
As a ready-to-use solution, you could use aioconsole library.作为即用型解决方案,您可以使用aioconsole库。 It implements a similar approach, but also provide additional useful asynchronous equivalents to
input
, print
, exec
and code.interact
:它实现了类似的方法,但也提供了额外有用的异步等价物
input
、 print
、 exec
和code.interact
:
from aioconsole import get_standard_streams
async def main():
reader, writer = await get_standard_streams()
Let's try to figure out how the function connect_stdin_stdout
works.让我们试着弄清楚函数
connect_stdin_stdout
是如何工作的。
loop = asyncio.get_event_loop()
StreamReader
instance.StreamReader
实例。reader = asyncio.StreamReader()
Generally, StreamReader/StreamWriter
classes are not intended to be directly instantiated and should only be used as a result of functions such as open_connection()
and start_server()
.通常,
StreamReader/StreamWriter
类不打算直接实例化,只能作为open_connection()
和start_server()
等函数的结果使用。 StreamReader
provides a buffered asynchronous interface to some data stream. StreamReader
为某些数据流提供缓冲的异步接口。 Some source(library code) calls its functions such as feed_data
, feed_eof
, the data is buffered and can be read using the documented interface coroutine read()
, readline()
, and etc.一些源代码(库代码)调用它的函数,例如
feed_data
、 feed_eof
,数据被缓冲并且可以使用文档化的接口协程read()
、 readline()
等read()
。
StreamReaderProtocol
instance.StreamReaderProtocol
实例。protocol = asyncio.StreamReaderProtocol(reader)
This class is derived from asyncio.Protocol
and FlowControlMixin
and helps to adapt between Protocol
and StreamReader
.此类派生自
asyncio.Protocol
和FlowControlMixin
,有助于在Protocol
和StreamReader
之间进行调整。 It overrides such Protocol
methods as data_received
, eof_received
and calls StreamReader
methods feed_data
.它覆盖诸如
data_received
、 eof_received
类的Protocol
方法并调用StreamReader
方法feed_data
。
stdin
in the event loop.stdin
。await loop.connect_read_pipe(lambda: protocol, sys.stdin)
The connect_read_pipe
function takes as a pipe
parameter a file-like object. connect_read_pipe
函数将类似文件的对象作为pipe
参数。 stdin
is a file-like object. stdin
是一个类似文件的对象。 From now, all data read from the stdin
will fall into the StreamReaderProtocol
and then pass into StreamReader
从现在开始,所有从
stdin
读取的数据都将落入StreamReaderProtocol
,然后传入StreamReader
stdout
in the event loop.stdout
。w_transport, w_protocol = await loop.connect_write_pipe(FlowControlMixin, sys.stdout)
In connect_write_pipe
you need to pass a protocol factory that creates protocol instances that implement flow control logic for StreamWriter.drain()
.在
connect_write_pipe
您需要传递一个协议工厂,该工厂创建实现StreamWriter.drain()
流控制逻辑的协议实例。 This logic is implemented in the class FlowControlMixin
.该逻辑在
FlowControlMixin
类中实现。 Also StreamReaderProtocol
inherited from it. StreamReaderProtocol
继承自它。
StreamWriter
instance.StreamWriter
实例。writer = asyncio.StreamWriter(w_transport, w_protocol, reader, loop)
This class forwards the data passed to it using functions write()
, writelines()
and etc. to the underlying transport
.此类使用函数
write()
、 writelines()
等将传递给它的数据转发到底层transport
。
protocol
is used to support the drain()
function to wait for the moment that the underlying transport has flushed its internal buffer and is available for writing again. protocol
用于支持drain()
函数等待底层传输已刷新其内部缓冲区并可以再次写入的那一刻。
reader
is an optional parameter and can be None
, it is also used to support the drain()
function, at the start of this function it is checked if an exception was set for the reader, for example, due to a connection lost (relevant for sockets and bidirectional connections), then drain()
will also throw an exception. reader
是一个可选参数,可以是None
,它还用于支持drain()
函数,在此函数开始时检查是否为 reader 设置了异常,例如,由于连接丢失(相关对于套接字和双向连接),那么drain()
也会抛出异常。
You can read more about StreamWriter
and drain()
function in this great answer .您可以在这个很好的答案中阅读有关
StreamWriter
和drain()
函数的更多信息。
To read lines with \\r\\n
separator readuntil can be used要使用
\\r\\n
分隔符读取行,可以使用readuntil
This is another way you can async read from stdin (reads a single line at a time).这是您可以从 stdin 异步读取的另一种方式(一次读取一行)。
async def async_read_stdin()->str:
loop = asyncio.get_event_loop()
return await loop.run_in_executor(None, sys.stdin.readline)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.