trioにある便利な関数move_on_after()とmove_on_at()を紹介します。
move_on_after
with move_on_after(秒数)
のようにしてwithブロックを作ることができ、指定した秒数経つとブロックを抜けます。例えば
import trio
async def main():
start_time = trio.current_time()
with trio.move_on_after(3):
while True:
elapsed_time = trio.current_time() - start_time
print(f"elapsed_time={elapsed_time:.1f}")
await trio.sleep(1)
elapsed_time = trio.current_time() - start_time
print(f"done (elapsed_time={elapsed_time:.1f})")
trio.run(main)
elapsed_time=0.0
elapsed_time=1.0
elapsed_time=2.0
done (elapsed_time=3.0)
-
trio.current_time()
は現在の時間を秒単位で取得する関数です -
while True
のループは中でawait trio.sleep(1)
を使っているため1秒周期で回る無限ループです- 無限ループですが
with trio.move_on_after(3)
のブロック内にあるため3秒経ったら抜けます - 抜けるのは
await
で非同期関数が呼ばれたタイミングです(ここではawait trio.sleep(1)
)
- 無限ループですが
尚、timeoutで抜けたかどうかはmove_on_after()
の返り値のCancelScopeのcancelled_caughtで分かります。
timeoutで抜けた場合はTrueとなります。例えば
import trio
async def main():
with trio.move_on_after(3) as cancel_scope:
for _ in range(5):
await trio.sleep(1)
print(f"cancelled_caught={cancel_scope.cancelled_caught}")
trio.run(main)
cancelled_caught=True
ここでmove_on_after()
の引数を6にするとタイムアウトで抜けなくなり、実行結果はcancelled_caught=False
となります。
move_on_at
with move_on_at(秒数)
のようにwithブロックを作ることができます。
move_on_after()
はtimeoutまでの秒数を指定する関数でしたが、move_on_at()
はtimeoutの時刻を指定します。例えば
import trio
async def main():
start_time = trio.current_time()
deadline = start_time + 3
with trio.move_on_at(deadline):
while True:
elapsed_time = trio.current_time() - start_time
print(f"elapsed_time={elapsed_time:.1f}")
await trio.sleep(1)
elapsed_time = trio.current_time() - start_time
print(f"done (elapsed_time={elapsed_time:.1f})")
trio.run(main)
elapsed_time=0.0
elapsed_time=1.0
elapsed_time=2.0
done (elapsed_time=3.0)
尚、timeoutの時刻(deadline)は動的に変えることができます。
move_on_at()
の返り値のCancelScopeのdeadlineを更新すればよいです。
上の例のtimeoutを3秒ではなく5秒に変更してみます。
import trio
async def main():
start_time = trio.current_time()
deadline = start_time + 3
with trio.move_on_at(deadline) as cancel_scope:
cancel_scope.deadline = start_time + 5
while True:
elapsed_time = trio.current_time() - start_time
print(f"elapsed_time={elapsed_time:.1f}")
await trio.sleep(1)
elapsed_time = trio.current_time() - start_time
print(f"done (elapsed_time={elapsed_time:.1f})")
trio.run(main)
elapsed_time=0.0
elapsed_time=1.0
elapsed_time=2.0
elapsed_time=3.0
elapsed_time=4.0
done (elapsed_time=5.0)
また、move_on_after()
と同様にCancelScope.cancelled_caught
で、timeoutしたかどうかが分かります。