内部でasync を呼ぶ関数はなぜasync defと宣言する必要があるのか?

pythonでasync/awaitを使ってコードを書くと、

async def はコルーチンの定義と書いてある。 コルーチンは作りすぎると分岐予測に失敗しパフォーマンスが落ちるため、コルーチンを作るのは最小に抑えた方がいいよね、と考えた。

その結果まず以下の様なコードを考えた。 func_with_io_inside()にはasync defをつけず、非コルーチンとするもの。 しかしこのコードはエラーになる。

import asyncio


async def iofunc():
    print("iofunc")
    # exe io
    await asyncio.sleep(1)


def func_with_io_inside():
    print("func_with_io_inside")
    await iofunc()


async def main():
    await func_with_io_inside()


asyncio.run(main())

"await" allowed only within async functionとなってしまう。 動く様に書き直したものを以下に示す。 func_with_io_inside()にもasync defをつけ、その呼び出しもawaitする様に変更

import asyncio


async def iofunc():
    print("iofunc")
    # exe io
    await asyncio.sleep(1)


async def func_with_io_inside():
    print("func_with_io_inside")
    await iofunc()


async def main():
    await func_with_io_inside()


asyncio.run(main())

awaitでコルーチンを待つためには外側をasync defでコルーチンを定義する必要がある。 これではコルーチン増えてパフォーマンスでないと思った。

ただ、コルーチンが必要となる多くがIO待ちが発生する時で、その場合コルーチンの切り替えコストはIO待ちに比べて遥かに低いため大きな問題にはならないらしい。 妥当な選択でpythonらしいと思う。 ただ好きではない。

他にもasync defを必須とするのは呼び出し側でawait忘れを防止するためもある。

以下を参照した。

stackoverflow.com

lukasa.co.uk