Если вы хотите использовать ввод с клавиатуры для выхода, вот решение для Linux и Mac OS X. Вы можете использовать модуль Python msvcrt , чтобы сделать нечто подобное в Windows.
Я скопировал echo-client.py
из учебника по трио и добавил «НОВЫЙ» комментарий к трем добавленным блокам кода. В REPL вы можете набрать 'q', чтобы отменить область питомника и выйти:
# -- NEW
import termios, tty
import sys
import trio
PORT = 12345
BUFSIZE = 16384
# -- NEW
async def keyboard():
"""Return an iterator of characters from stdin."""
stashed_term = termios.tcgetattr(sys.stdin)
try:
tty.setcbreak(sys.stdin, termios.TCSANOW)
while True:
yield await trio.run_sync_in_worker_thread(
sys.stdin.read, 1,
cancellable=True
)
finally:
termios.tcsetattr(sys.stdin, termios.TCSANOW, stashed_term)
async def sender(client_stream):
print("sender: started!")
while True:
data = b"async can sometimes be confusing, but I believe in you!"
print("sender: sending {!r}".format(data))
await client_stream.send_all(data)
await trio.sleep(1)
async def receiver(client_stream):
print("receiver: started!")
while True:
data = await client_stream.receive_some(BUFSIZE)
print("receiver: got data {!r}".format(data))
if not data:
print("receiver: connection closed")
sys.exit()
async def parent():
print("parent: connecting to 127.0.0.1:{}".format(PORT))
client_stream = await trio.open_tcp_stream("127.0.0.1", PORT)
async with client_stream:
async with trio.open_nursery() as nursery:
print("parent: spawning sender...")
nursery.start_soon(sender, client_stream)
print("parent: spawning receiver...")
nursery.start_soon(receiver, client_stream)
# -- NEW
async for key in keyboard():
if key == 'q':
nursery.cancel_scope.cancel()
trio.run(parent)
Вызов tty.setcbreak
переводит терминал в небуферизованный режим, поэтому вам не нужно нажимать клавишу возврата, пока программа не получит ввод. Это также предотвращает отображение символов на экране. Кроме того, как следует из названия, он позволяет Ctrl-C
работать как обычно.
В блоке finally
termios.tcsetattr
восстанавливает терминал в любом режиме, в котором он находился до tty.setcbreak
. Таким образом, ваш терминал возвращается в нормальное состояние при выходе.
sys.stdin.read
создается в отдельном потоке, потому что он должен работать в режиме блокировки (плохо в асинхронном контексте). Причина в том, что stdin
делится описанием файла с stdout
и stderr
. Установка неблокирующего значения stdin
также приведет к неблокирующему stdout
как побочному эффекту, что может вызвать проблемы с функцией print
(усечение в моем случае).
Межпроцессное взаимодействие
Вот базовый пример отмены одного процесса Trio из другого с помощью сокета:
# infinite_loop.py
import trio
async def task():
while True:
print("ping")
await trio.sleep(0.5)
async def quitter(cancel_scope):
async def quit(server_stream):
await server_stream.receive_some(1024)
cancel_scope.cancel()
await trio.serve_tcp(quit, 12346)
async def main():
async with trio.open_nursery() as nursery:
nursery.start_soon(task)
nursery.start_soon(quitter, nursery.cancel_scope)
trio.run(main)
# slayer.py
import trio
async def main():
async with await trio.open_tcp_stream("127.0.0.1", 12346) as s:
await trio.sleep(3)
await s.send_all(b'quit')
trio.run(main)