本文介绍了使用Python3 Trio创建异步程序时经常使用的模式。
如果您想进一步了解Trio和pytest-trio,建议您使用原始文档。
- 三重奏:https://trio.readthedocs.io/en/latest/
- pytest-trio:https://pytest-trio.readthedocs.io/en/latest/
运行环境
- Python 3.7
- 三重奏0.11
- pytest-trio 0.5.2
同时执行异步处理
首先,它是同时执行基本方法和异步方法的一种方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import trio async def func1(): await trio.sleep(1) print("func1 finished") async def func2(): await trio.sleep(1) print("func2 finished") async def main(): async with trio.open_nursery() as nursery: # func1, func2 を同時に実行 nursery.start_soon(func1) nursery.start_soon(func2) # 両方のメソッドが完了するのを待つ print("all methods finished") trio.run(main) |
执行后,看起来像这样。
1 2 3 | func2 finished func1 finished all methods finished |
您还可以将参数传递给每个方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import trio async def func1(t): await trio.sleep(t) print("func1 finished") async def func2(t1, t2): await trio.sleep(t1 + t2) print("func2 finished") async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(func1, 1.0) nursery.start_soon(func2, 0.5, 1.0) print("all methods finished") trio.run(main) |
执行结果。
1 2 3 | func1 finished func2 finished all methods finished |
执行多个异步方法并在其中一个完成时中断其他处理
这是一种等待满足多个条件之一的模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import trio async def cond1(nursery): await trio.sleep(1.0) print("cond1 satisfied") nursery.cancel_scope.cancel() async def cond2(nursery): await trio.sleep(0.5) print("cond2 satisfied") nursery.cancel_scope.cancel() async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(cond1, nursery) nursery.start_soon(cond2, nursery) print("one condition satisfied") trio.run(main) |
执行结果。
1 2 | cond2 satisfied one condition satisfied |
您可以看到,当
如果创建
包装器方法,则不必将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import trio async def cond1(): await trio.sleep(1.0) print("cond1 satisfied") async def cond2(): await trio.sleep(0.5) print("cond2 satisfied") async def wrapper(func, nursery): await func() nursery.cancel_scope.cancel() async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(wrapper, cond1, nursery) nursery.start_soon(wrapper, cond2, nursery) print("one condition satisfied") trio.run(main) |
一个过程满足某些条件,然后再启动另一个
用于某些模式,例如等待与数据库的连接以开始读写数据,或等待完成一个计算以执行另一计算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import trio async def connect_db(*, task_status=trio.TASK_STATUS_IGNORED): await trio.sleep(1.0) print("connected to DB") # nursery にタスクが開始できたことを通知する task_status.started() try: await trio.sleep_forever() finally: print("disconnected from DB") async def write_data(data): await trio.sleep(0.5) print(f"write data to DB: {data}") async def read_data(): await trio.sleep(1.0) print("read data from DB") return "data" async def main(): async with trio.open_nursery() as nursery: # nursery.start を使うと、タスクが開始された通知が来るまで待つ await nursery.start(connect_db) # DB への接続を待ってデータの読み書きを開始 await write_data("foo") _ = await read_data() nursery.cancel_scope.cancel() print("transaction finished") trio.run(main) |
执行结果。
1 2 3 4 5 | connected to DB write data to DB: foo read data from DB disconnected from DB transaction finished |
等待与数据库的正确连接,您可以看到
通过以异步方法在
一段时间后取消处理
当您要为异步处理设置超时时,这是一种模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import trio async def func(name, t): try: await trio.sleep(t) print(f"{name} finished") except trio.Cancelled: print(f"{name} canceled") async def main(): # 2.5秒でタイムアウト with trio.move_on_after(2.5): async with trio.open_nursery() as nursery: nursery.start_soon(func, "func1", 1.0) nursery.start_soon(func, "func2", 2.0) nursery.start_soon(func, "func3", 3.0) print("timeout") trio.run(main) |
执行结果。
1 2 3 4 | func1 finished func2 finished func3 canceled timeout |
您可以看到在2.5秒内完成的
跳过睡眠时间以减少测试时间
使用
pytest进行测试时,可以使用pytest-trio的
首先,在
pytest.ini
1 2 | [pytest] trio_mode = true |
让我们运行以下测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import time import trio async def test1(): v0, t0 = trio.current_time(), time.time() await trio.sleep(1) v1, t1 = trio.current_time(), time.time() print(f"test1: virtual time={v1 - v0}sec, real time={t1 - t0}sec") assert 1 + 1 == 2 async def test2(autojump_clock): v0, t0 = trio.current_time(), time.time() await trio.sleep(1) v1, t1 = trio.current_time(), time.time() print(f"test2: virtual time={v1 - v0}sec, real time={t1 - t0}sec") assert 1 + 1 == 2 |
执行结果。
1 2 | test1: virtual time=1.0040155599999707sec, real time=1.0039751529693604sec test2: virtual time=1.0sec, real time=0.0003070831298828125sec |
可以看到,三重奏的经过时间和正常编写的
如果使用
终于
Python3很好!三重奏很棒!
如果还有其他有用的模式,我会不时更新本文,因此,如果您知道诸如"您有这样的设备吗?"或"有这么有用的功能"之类的信息,请多多关照。可以发表评论。