LoginSignup
1
0

More than 1 year has passed since last update.

trioによる並行処理⑥(try~finallyの罠と回避策)

Last updated at Posted at 2022-10-03

目次

try~finallyの罠

trioを使っている時、try~finallyの構文に注意が必要です。例えば

async def func():
    try:
        print("try start")
        await trio.sleep(1)
        print("try done")
    finally:
        print("finally start")
        await trio.sleep(0)
        print("finally done")

のような関数があるとき、finally内の全処理は常に実行されると思ってしまう方も居るのではないでしょうか。
しかし、下記サンプルが示すようにそうなりません。

サンプル
import trio

async def func():
    try:
        print("try start")
        await trio.sleep(1)
        print("try done")
    finally:
        print("finally start")
        await trio.sleep(0)
        print("finally done")

async def main():
    with trio.move_on_after(0.5):
        await func()

trio.run(main)
実行結果
try start
finally start

"finally done"が出力されていません。
つまり、move_on_afterCancelScopeなどのブロック内でtry~finallyを使った場合、タイムアウトやキャンセルで処理が中断していれば、finally内のawait 非同期関数()以降の処理が実行されません。
これを認識していないとバグの原因になってしまいます。

回避策

前回紹介したCancelScopeshieldによって回避できます。

サンプル
import trio

async def func():
    try:
        print("try start")
        await trio.sleep(1)
        print("try done")
    finally:
        with trio.CancelScope(shield=True):
            print("finally start")
            await trio.sleep(0)
            print("finally done")

async def main():
    with trio.move_on_after(0.5):
        await func()

trio.run(main)
実行結果
try start
finally start
finally done

shieldをTrueにするとブロック外のタイムアウトやキャンセルによって終了しなくなるため、finally内の全処理を実行することができました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0