如何手动退出无限三重循环,就像三重奏的教程 echo client
How to manually exit an infinite trio-loop, like the trio's tutorial echo client
除了使用 Ctrl-C
或使用超时之外,是否有其他方法可以手动退出 trio 无限循环,例如 trio 教程 https://trio.readthedocs.io/en/latest/tutorial.html#an-echo-client 中的 echo 客户端?
我的想法是使用从另一个 python 脚本调用 echo 客户端,并且能够使用相同的 python 脚本任意关闭它。我正在考虑使用标志(也许是事件?)作为开关来触发托儿所中的 cancel_scope.cancel()
。但我不知道如何触发开关。下面是我尝试修改教程回显客户端代码。
import sys
import trio
PORT = 12345
BUFSIZE = 16384
FLAG = 1 # FLAG is a global variable
async def sender(client_stream):
print("sender: started")
while FLAG:
data = b'async can sometimes be confusing but I believe in you!'
print(f"sender: sending {data}")
await client_stream.send_all(data)
await trio.sleep(1)
async def receiver(client_stream):
print("recevier: started!")
while FLAG:
data = await client_stream.receive_some(BUFSIZE)
print(f"receiver: got data {data}")
if not data:
print("receiver: connection closed")
sys.exit()
async def checkflag(nursery): # function to trigger cancel()
global FLAG
if not FLAG:
nursery.cancel_scope.cancel()
else:
# keep this task running if not triggered, but how to trigger it,
# without Ctrl-C or timeout?
await trio.sleep(1)
async def parent():
print(f"parent: connecting to 127.0.0.1:{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)
print("parent: spawning checkflag...")
nursery.start_soon(checkflag, nursery)
print('Close nursery...')
print("Close stream...")
trio.run(parent)
我发现我无法在 trio.run()
之后向 python REPL 输入任何命令来手动更改 FLAG
,我想知道我是否从另一个脚本,如何在托儿所中触发 cancel_scope.cancel()
?或者,还有更好的方法?非常感谢所有帮助。谢谢。
有很多方法可以做到这一点。为什么不直接使用 Ctrl-C
?对我来说似乎完全有效。
如果你真的不想使用Ctrl-C
,那么你将需要一个函数来监听输入和更新FLAG
(或者直接退出程序;我不老实说,你根本不需要 FLAG
逻辑)。
例如,您可以有一个从文件轮询/从数据库读取/侦听终端输入等的函数,并并行使用此 运行。侦听器应 运行 作为同一个 Python 脚本中的独立工作人员。但取决于您选择如何执行此操作,更改外部输入的函数可以是一个独立的脚本
如果你想使用键盘输入退出,这里是 Linux 和 Mac OS X 的解决方案。你可以使用 Python msvcrt 模块在 Windows.
上做类似的事情
我从 the Trio tutorial 复制了 echo-client.py
并在添加的三个代码块上添加了 "NEW" 注释。在 REPL 中,您可以键入 'q' 取消 nursery 作用域并退出:
# -- 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
的调用将终端置于非缓冲模式,因此您不必在程序接收输入之前按 return。它还可以防止字符回显到屏幕上。此外,顾名思义,它允许 Ctrl-C
正常工作。
在 finally
块中,termios.tcsetattr
将终端恢复到 tty.setcbreak
之前的任何模式。所以你的终端在退出时恢复正常。
sys.stdin.read
在单独的线程中产生,因为它需要 运行 在阻塞模式下(在异步上下文中不好)。原因是 stdin
shares its file description 与 stdout
和 stderr
。将 stdin
设置为 non-blocking 也会将 stdout
设置为 non-blocking 作为副作用,这可能会导致 print
函数出现问题(t运行阳离子在我的情况下)。
Inter-process 通讯
这是一个使用套接字从另一个取消一个 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)
除了使用 Ctrl-C
或使用超时之外,是否有其他方法可以手动退出 trio 无限循环,例如 trio 教程 https://trio.readthedocs.io/en/latest/tutorial.html#an-echo-client 中的 echo 客户端?
我的想法是使用从另一个 python 脚本调用 echo 客户端,并且能够使用相同的 python 脚本任意关闭它。我正在考虑使用标志(也许是事件?)作为开关来触发托儿所中的 cancel_scope.cancel()
。但我不知道如何触发开关。下面是我尝试修改教程回显客户端代码。
import sys
import trio
PORT = 12345
BUFSIZE = 16384
FLAG = 1 # FLAG is a global variable
async def sender(client_stream):
print("sender: started")
while FLAG:
data = b'async can sometimes be confusing but I believe in you!'
print(f"sender: sending {data}")
await client_stream.send_all(data)
await trio.sleep(1)
async def receiver(client_stream):
print("recevier: started!")
while FLAG:
data = await client_stream.receive_some(BUFSIZE)
print(f"receiver: got data {data}")
if not data:
print("receiver: connection closed")
sys.exit()
async def checkflag(nursery): # function to trigger cancel()
global FLAG
if not FLAG:
nursery.cancel_scope.cancel()
else:
# keep this task running if not triggered, but how to trigger it,
# without Ctrl-C or timeout?
await trio.sleep(1)
async def parent():
print(f"parent: connecting to 127.0.0.1:{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)
print("parent: spawning checkflag...")
nursery.start_soon(checkflag, nursery)
print('Close nursery...')
print("Close stream...")
trio.run(parent)
我发现我无法在 trio.run()
之后向 python REPL 输入任何命令来手动更改 FLAG
,我想知道我是否从另一个脚本,如何在托儿所中触发 cancel_scope.cancel()
?或者,还有更好的方法?非常感谢所有帮助。谢谢。
有很多方法可以做到这一点。为什么不直接使用 Ctrl-C
?对我来说似乎完全有效。
如果你真的不想使用Ctrl-C
,那么你将需要一个函数来监听输入和更新FLAG
(或者直接退出程序;我不老实说,你根本不需要 FLAG
逻辑)。
例如,您可以有一个从文件轮询/从数据库读取/侦听终端输入等的函数,并并行使用此 运行。侦听器应 运行 作为同一个 Python 脚本中的独立工作人员。但取决于您选择如何执行此操作,更改外部输入的函数可以是一个独立的脚本
如果你想使用键盘输入退出,这里是 Linux 和 Mac OS X 的解决方案。你可以使用 Python msvcrt 模块在 Windows.
上做类似的事情我从 the Trio tutorial 复制了 echo-client.py
并在添加的三个代码块上添加了 "NEW" 注释。在 REPL 中,您可以键入 'q' 取消 nursery 作用域并退出:
# -- 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
的调用将终端置于非缓冲模式,因此您不必在程序接收输入之前按 return。它还可以防止字符回显到屏幕上。此外,顾名思义,它允许 Ctrl-C
正常工作。
在 finally
块中,termios.tcsetattr
将终端恢复到 tty.setcbreak
之前的任何模式。所以你的终端在退出时恢复正常。
sys.stdin.read
在单独的线程中产生,因为它需要 运行 在阻塞模式下(在异步上下文中不好)。原因是 stdin
shares its file description 与 stdout
和 stderr
。将 stdin
设置为 non-blocking 也会将 stdout
设置为 non-blocking 作为副作用,这可能会导致 print
函数出现问题(t运行阳离子在我的情况下)。
Inter-process 通讯
这是一个使用套接字从另一个取消一个 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)