Мне нужно написать две программы, которые будут запускаться как родительский процесс и его дочерний процесс. Родительский процесс порождает дочерний процесс, и затем они связываются через пару каналов, связанных с дочерним stdin и stdout. Общение одноранговое, поэтому мне нужно asyncio. Простой цикл чтения / ответа не подойдет.
Я написал родителю. Нет проблем, потому что asyncio
предоставляет все, что мне нужно в create_subprocess_exec()
.
Однако я не знаю, как создать подобную потоковую программу чтения / записи для ребенка. Я не ожидал никаких проблем. потому что каналы уже созданы и файловые дескрипторы 0 и 1 готовы к использованию при запуске дочернего процесса. Соединение не должно быть открыто, процесс не должен быть запущен.
Это моя неработающая попытка:
import asyncio
import sys
_DEFAULT_LIMIT = 64 * 1024
async def connect_stdin_stdout(limit=_DEFAULT_LIMIT, loop=None):
if loop is None:
loop = asyncio.get_event_loop()
reader = asyncio.StreamReader(limit=limit, loop=loop)
protocol = asyncio.StreamReaderProtocol(reader, loop=loop)
r_transport, _ = await loop.connect_read_pipe(lambda: protocol, sys.stdin)
w_transport, _ = await loop.connect_write_pipe(lambda: protocol, sys.stdout)
writer = asyncio.StreamWriter(w_transport, protocol, reader, loop)
return reader, writer
Проблема в том, что у меня есть два транспорта, где я должен иметь один. Функция не выполняется, потому что она пытается установить транспорт протокола дважды:
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
await loop.connect_write_pipe(lambda: protocol, sys.stdout)
# !!!! assert self._transport is None, 'Transport already set'
Я пытался передать фиктивный протокол на первую строку, но эта строка также не верна, потому что нужны оба транспорта, а не один:
writer = asyncio.StreamWriter(w_transport, protocol, reader, loop)
Полагаю, мне нужно как-то объединить два однонаправленных транспорта в один двунаправленный. Или мой подход совершенно неверный? Не могли бы вы дать мне совет?
ОБНОВЛЕНИЕ : после некоторого теста это, кажется, работает (но мне не очень хорошо):
async def connect_stdin_stdout(limit=_DEFAULT_LIMIT, loop=None):
if loop is None:
loop = asyncio.get_event_loop()
reader = asyncio.StreamReader(limit=limit, loop=loop)
protocol = asyncio.StreamReaderProtocol(reader, loop=loop)
dummy = asyncio.Protocol()
await loop.connect_read_pipe(lambda: protocol, sys.stdin) # sets read_transport
w_transport, _ = await loop.connect_write_pipe(lambda: dummy, sys.stdout)
writer = asyncio.StreamWriter(w_transport, protocol, reader, loop)
return reader, writer