簡體   English   中英

python asyncio如何讀取StdIn並寫入StdOut?

[英]python asyncio how to read StdIn and write to StdOut?

我需要異步讀取 StdIn 以獲取消息(json 由 \\r\\n 終止),並在處理異步后將更新的消息寫入 StdOut。

目前我正在同步進行,例如:

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

如何執行相同但異步的操作?

這是使用異步流(對於 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())

作為即用型解決方案,您可以使用aioconsole庫。 它實現了類似的方法,但也提供了額外有用的異步等價物inputprintexeccode.interact

from aioconsole import get_standard_streams

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

更新:

讓我們試着弄清楚函數connect_stdin_stdout是如何工作的。

  1. 獲取當前事件循環:
loop = asyncio.get_event_loop()
  1. 創建StreamReader實例。
reader = asyncio.StreamReader()

通常, StreamReader/StreamWriter類不打算直接實例化,只能作為open_connection()start_server()等函數的結果使用。 StreamReader為某些數據流提供緩沖的異步接口。 一些源代碼(庫代碼)調用它的函數,例如feed_datafeed_eof ,數據被緩沖並且可以使用文檔化的接口協程read()readline()read()

  1. 創建StreamReaderProtocol實例。
protocol = asyncio.StreamReaderProtocol(reader)

此類派生自asyncio.ProtocolFlowControlMixin ,有助於在ProtocolStreamReader之間進行調整。 它覆蓋諸如data_receivedeof_received類的Protocol方法並調用StreamReader方法feed_data

  1. 在事件循環中注冊標准輸入流stdin
await loop.connect_read_pipe(lambda: protocol, sys.stdin)

connect_read_pipe函數將類似文件的對象作為pipe參數。 stdin是一個類似文件的對象。 從現在開始,所有從stdin讀取的數據都將落入StreamReaderProtocol ,然后傳入StreamReader

  1. 在事件循環中注冊標准輸出流stdout
w_transport, w_protocol = await loop.connect_write_pipe(FlowControlMixin, sys.stdout)

connect_write_pipe您需要傳遞一個協議工廠,該工廠創建實現StreamWriter.drain()流控制邏輯的協議實例。 該邏輯在FlowControlMixin類中實現。 StreamReaderProtocol繼承自它。

  1. 創建StreamWriter實例。
writer = asyncio.StreamWriter(w_transport, w_protocol, reader, loop)

此類使用函數write()writelines()等將傳遞給它的數據轉發到底層transport

protocol用於支持drain()函數等待底層傳輸已刷新其內部緩沖區並可以再次寫入的那一刻。

reader是一個可選參數,可以是None ,它還用於支持drain()函數,在此函數開始時檢查是否為 reader 設置了異常,例如,由於連接丟失(相關對於套接字和雙向連接),那么drain()也會拋出異常。

您可以在這個很好的答案中閱讀有關StreamWriterdrain()函數的更多信息。

更新 2:

要使用\\r\\n分隔符讀取行,可以使用readuntil

這是您可以從 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM