简体   繁体   English

python asyncio如何读取StdIn并写入StdOut?

[英]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 :它实现了类似的方法,但也提供了额外有用的异步等价物inputprintexeccode.interact

from aioconsole import get_standard_streams

async def main():
    reader, writer = await get_standard_streams()

Update:更新:

Let's try to figure out how the function connect_stdin_stdout works.让我们试着弄清楚函数connect_stdin_stdout是如何工作的。

  1. Get the current event loop:获取当前事件循环:
loop = asyncio.get_event_loop()
  1. Create 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_datafeed_eof ,数据被缓冲并且可以使用文档化的接口协程read()readline()read()

  1. Create 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.ProtocolFlowControlMixin ,有助于在ProtocolStreamReader之间进行调整。 It overrides such Protocol methods as data_received , eof_received and calls StreamReader methods feed_data .它覆盖诸如data_receivedeof_received类的Protocol方法并调用StreamReader方法feed_data

  1. Register standard input stream 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

  1. Register standard output stream 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继承自它。

  1. Create 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 .您可以在这个很好的答案中阅读有关StreamWriterdrain()函数的更多信息。

Update 2:更新 2:

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.

相关问题 Python asyncio子进程连续写入stdin和读取stdout / stderr - Python asyncio subprocess write stdin and read stdout/stderr continuously 如何阅读和检查python中的stdin / stdout? - How to read and check stdin/stdout in python? 重复写入stdin并从python中读取进程的stdout - Repeatedly write to stdin and read from stdout of a process from python python子进程多个stdin.write和stdout.read - python subprocess multiple stdin.write and stdout.read 如何在 python 中广泛和/或交替地从 stdout 和/或 stderr 读取并写入进程的 stdin? - How to wildly and/or alternatingly read from stdout and/or stderr and write to stdin of a process in python? 如何运行只能写入STDOUT并从STDIN读取的脚本? - How to run a script that can only write to STDOUT and read from STDIN? communic()和.stdin.write,.stdout.read或.stderr.read - python之间的区别 - difference between communicate() and .stdin.write, .stdout.read or .stderr.read - python 如何为stdin / stdout创建asyncio流读取器/写入器? - How to create asyncio stream reader/writer for stdin/stdout? 在python中长时间运行的子进程上写入stdin并从stdout读取 - write to stdin and read from stdout on long-running child process in python 如何在进程stdin 仍在运行时写入进程stdin 并从其stdout 中读取? - how can I write to a processes stdin and read from its stdout while it is still running?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM