chakokuのブログ(rev4)

テック・コミック・ごくまれにチャリ

pythonのasyncioが全く分からない

普段、非同期処理は必要ないのだけど、、たまたまasyncioに出くわして、ちょっとPythonのドキュメントを読んでみたがどう動くのか全く分からない(実行順番が想像できない)。
以下のサイト等、がっつり説明しているサイトで勉強しないとだめなのかも。

Async IO in Python: A Complete Walkthrough – Real Python

なぜこれほど分からないのか考えた。自分は非同期実装に関するプログラミングモデルが頭の中にない。だから類推がきかない。pythonのasyncioの説明も非同期実装のチュートリアルではなくて、Pythonではこう実装していますという説明だろう。土台となる基礎知識がない中で、動作だけ説明されてもなぜその式や関数があるのか、どう使うのか?何がうれしいのかまで理解が及ばない。非同期実装が一番頻繁に使われているのはJavaScriptと思えて、JSはユーザも多くて解説記事も多いだろう。だから、、まずJSで非同期実装について基礎を学んでから、Pythonの実装を学ぶべきではないかと思った。


Pythonのドキュメント
コルーチンと Task — Python 3.9.4 ドキュメント

テストプログラム

import asyncio
import time

async def d():
     print('D1')
     await asyncio.sleep(0)
     print('D2')
     await asyncio.sleep(1)
     print('D3')

async def e():
     print('E1')
     await asyncio.sleep(0)
     print('E2')
     await asyncio.sleep(4)
     print('E3')


async def hoge():
   print("L1")
   task1 = asyncio.create_task(d())
   print("L2")
   task2 = asyncio.create_task(e())
   print("L3")
   await task1
   print("L4")
   await task2
   print("L5")

print("start")
asyncio.run(hoge())
print("bye")

実行結果

$ python3 test0.py
start
L1
L2
L3
D1
E1
D2
E2
D3
L4
E3
L5
bye

テストプログラム

import asyncio
import time

async def d():
     print('D1')
     await asyncio.sleep(0)
     print('D2')
     await asyncio.sleep(1)
     print('D3')

async def e():
     print('E1')
     await asyncio.sleep(0)
     print('E2')
     await asyncio.sleep(4)
     print('E3')


async def hoge():
   print("L1")
   task1 = asyncio.create_task(d())
   print("L2")
   task2 = asyncio.create_task(e())
   print("L3")


print("start")
asyncio.run(hoge())
print("bye")

実行結果

$ python3 test1.py
start
L1
L2
L3
D1 
E1
bye

漠然とした理解
asyncioは、、待ってくれる式や関数?に出くわすまで実行されない。。 awaitは待ってくれる式。。待ってくれる状態になって初めてawaitioで定義された関数は動き始める。。。また、関数内でsleepすると、他の待っているawaitioが動き始める。だけど、、task として生成すると、待たずに動き始める。awaitに出くわすと、自分の実行は一旦そこで止めて、他で待っているawaitableの実行を開始する。。うーん。。

■ご参考:がっつり読みたいJS解説記事

async/await 入門(JavaScript) - Qiita

(↓ちょっと宣伝が多いですが。。)
【JavaScript入門】5分で理解!async / awaitの使い方と非同期処理の書き方 | 侍エンジニアブログ

await - JavaScript | MDN

JavaScriptは如何にしてAsync/Awaitを獲得したのか Qiita版 - Qiita

JavaScript Promiseの本

複雑で長すぎてとても読む力はないけど、、コールバックから紆余曲折を経て、async/awaitが発明され、async/awaitを使うことでコードがすっきり書けることは分かった。
JavaScriptは如何にしてAsync/Awaitを獲得したのか Qiita版 - Qiita

■追記
分かったこと:
async/awaitは本来シングルスレッドで実行しているプログラムに非同期的な動作を簡潔に表現するために作り出された機構である

参照先文献(JS)より引用

Async Functionとawait式を使うことで非同期処理をまるで同期処理のように書けます。
重要なこととしてAsync FunctionはPromiseの上に作られた構文です。 そのためAsync Functionを理解するには、Promiseを理解する必要があることに注意してください。

前半の文書は、後半はよくわかる。どう見ても同期処理ぢゃないか!と思っていたから。async/awaitを使うことで、非同期処理を同期処理のように書けるということか。一見同期処理の裏側にある非同期というのが見えなくなっている。自分の視力では見えない。。