[英]Python asyncio subprocess write stdin and read stdout/stderr continuously
[英]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庫。 它實現了類似的方法,但也提供了額外有用的異步等價物input
、 print
、 exec
和code.interact
:
from aioconsole import get_standard_streams
async def main():
reader, writer = await get_standard_streams()
讓我們試着弄清楚函數connect_stdin_stdout
是如何工作的。
loop = asyncio.get_event_loop()
StreamReader
實例。reader = asyncio.StreamReader()
通常, StreamReader/StreamWriter
類不打算直接實例化,只能作為open_connection()
和start_server()
等函數的結果使用。 StreamReader
為某些數據流提供緩沖的異步接口。 一些源代碼(庫代碼)調用它的函數,例如feed_data
、 feed_eof
,數據被緩沖並且可以使用文檔化的接口協程read()
、 readline()
等read()
。
StreamReaderProtocol
實例。protocol = asyncio.StreamReaderProtocol(reader)
此類派生自asyncio.Protocol
和FlowControlMixin
,有助於在Protocol
和StreamReader
之間進行調整。 它覆蓋諸如data_received
、 eof_received
類的Protocol
方法並調用StreamReader
方法feed_data
。
stdin
。await loop.connect_read_pipe(lambda: protocol, sys.stdin)
connect_read_pipe
函數將類似文件的對象作為pipe
參數。 stdin
是一個類似文件的對象。 從現在開始,所有從stdin
讀取的數據都將落入StreamReaderProtocol
,然后傳入StreamReader
stdout
。w_transport, w_protocol = await loop.connect_write_pipe(FlowControlMixin, sys.stdout)
在connect_write_pipe
您需要傳遞一個協議工廠,該工廠創建實現StreamWriter.drain()
流控制邏輯的協議實例。 該邏輯在FlowControlMixin
類中實現。 StreamReaderProtocol
繼承自它。
StreamWriter
實例。writer = asyncio.StreamWriter(w_transport, w_protocol, reader, loop)
此類使用函數write()
、 writelines()
等將傳遞給它的數據轉發到底層transport
。
protocol
用於支持drain()
函數等待底層傳輸已刷新其內部緩沖區並可以再次寫入的那一刻。
reader
是一個可選參數,可以是None
,它還用於支持drain()
函數,在此函數開始時檢查是否為 reader 設置了異常,例如,由於連接丟失(相關對於套接字和雙向連接),那么drain()
也會拋出異常。
您可以在這個很好的答案中閱讀有關StreamWriter
和drain()
函數的更多信息。
要使用\\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.