async/awaitを使ったら遅くなった話【python】

2024/04/29に公開

ある日、pythonのasync/awaitを学ぼうと思い、この動画を見ながらコードを書いていました。

https://www.youtube.com/watch?v=KnNWw5HX20w

change_async関数の作成

そうしたら、「コルーチンに変換する関数作れば楽かも」と思い試しにコードを書いてみました。

async.py
#import
import time
import asyncio

import numpy as np

#this function can change to async function
async def change_async(func, *args, **keywords):
    return func(*args, **keywords)

#async main
async def async_main():
    xx = await change_async(np.arange, 0, 4)
    yy = await change_async(np.arange, 0, 4)

    xx, yy = np.meshgrid(xx, yy)

    for xi, x in enumerate(xx):
        for yi, y in enumerate(yy):
            print(x[xi], y[yi])

if __name__ == "__main__":
    #async_main run
    start = time.time()
    asyncio.run(async_main())
    end = time.time()
    print(f"execution speed of async_main: {end - start}")

このコードは、change_asyncという、関数をコルーチンに変換する関数を作り、np.arangeをコルーチンに変換し、awaitで並列処理しています。

その結果はこちら。

0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 0
3 1
3 2
3 3
execution speed of async_main: 0.004174232482910156

最初は、このコードの実行速度が遅くなっていることを知らず、成功したと思い込んでいました。

async/awaitありなしの比較

しかしその後、「これasync使わずに書いたコードよりどのくらい早いのかな」と思い、試してみました。

そのコードがこちら。

async.py
#async.py

#import
import time
import asyncio

import numpy as np

#this function can change to async function
async def change_async(func, *args, **keywords):
    return func(*args, **keywords)

#async main
async def async_main():
    xx = await change_async(np.arange, 0, 4)
    yy = await change_async(np.arange, 0, 4)

    xx, yy = np.meshgrid(xx, yy)

    for xi, x in enumerate(xx):
        for yi, y in enumerate(yy):
            print(x[xi], y[yi])

#main
def main():
    xx = np.arange(0, 4)
    yy = np.arange(0, 4)

    xx, yy = np.meshgrid(xx, yy)

    for xi, x in enumerate(xx):
        for yi, y in enumerate(yy):
            print(x[xi], y[yi])

if __name__ == "__main__":
    #async_main run
    start = time.time()
    asyncio.run(async_main())
    end = time.time()
    print(f"execution speed of async_main: {end - start}")

    #main run
    start = time.time()
    main()
    end = time.time()
    print(f"execution speed of main: {end - start}")

このコードは、さっきのasync_main関数とasyncではないmain関数の実行速度を比較できるようになっています。

このコードを実行した時、その真実を知ってしまいましたw

その結果がこちら。

0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 0
3 1
3 2
3 3
execution speed of async_main: 0.004174232482910156
0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 0
3 1
3 2
3 3
execution speed of main: 0.002992391586303711

そう、上(async_main)より下(main)の方が実行速度が早いのです。

おわり

このことから、async/awaitは必ずしも実行速度を速くさせるわけではないことが分かりました。むしろ、場合によっては実行速度を遅くさせる可能性もあります。

async/awaitは、ちゃんと実行速度が早くなることを確認してから使いましょう。

Discussion