はじめに
micropythonは普段使っているwindowsやmacと違い, アイコンをダブルクリックだけで複数のウィンドウを同時に起動するようなことはできないので, 複数のプロセスを同時に実行するためにプログラムを並行/並列処理をやらなければならない. そこにmicropythonが提供しているライブラリは_threadが現れました. しかしながら, micropythonドキュメント には_threadについての説明はないので, その代わりに豊富な関数を持っているuasyncio が多くのプログラマの注目を集めています.
マルチタスクとは?
マルチタスク(マルチプロセスも呼ばれる)は原則として並列/並行処理ではありません. 言い換えれば複数のプロセスを完璧な同期処理することはできません. CPUの構造によってシングルコアの場合はある瞬間に一つの処理しか実行できません. また, ESP32は二つのコア(デュアルコア)を持っていますが, デュアルコアによるマルチコア操作はサポートされていないらしいです. そしてマルチタスクはプログラマ処理の待ち時間の間にCPUを動作させ別の計算を行い, タスクの処理時間が短いなら並列/並行処理と同じような効果が期待されます. 代替品であるuasyncioはコルーチンを用いてマルチタスクを実現することができます.
プログラム
ここではシンプルなuasyncioによるマルチタスク処理の例を紹介します.
import uasyncio as asyncio
async def bar(x):
#回数をカウント
count = 0
while True:
count += 1
print('Instance: {} count: {}'.format(x, count))
#出力間隔
await asyncio.sleep(1) # Pause 1s
async def main():
for x in range(3):
#タスクを生成する
asyncio.create_task(bar(x))
#実行時間
await asyncio.sleep(10)
asyncio.run(main())
実行結果
実行結果は下図の示す通りにインスタンスごとに出力が十回行われました.
実際にこれは1秒間隔でインスタンス1-3をそれぞれ出力するプログラムなので, 図だけでなかなかわかりにくいですね. もし時間があったら実行してみると多分すぐにわかると思います.
ソースコード:解説していくよ
uasyncio
micropythonにはuasyncioを行うためのモジュールが標準的に組み込まれています. またasyncioはpythonに組み込まれています.
async def
uasyncioを使う前提として関数を定義するときにasyncを前に書く必要があります.
await asyncio.sleep()
前に述べたようにマルチタスク処理とは処理の待ち時間の間に別の処理を差し込むので, その間を定義する関数はawait asyncio.sleep()となります.
asyncio.create_task()
プロセスをタスクとして生成する関数です. 複数のプロセスを非同期処理する場合はこの関数を複数回呼び出す必要もあります.
asyncio.run(main())
main関数中に書いてあるuasyncio処理をすべて実行する関数です(main関数をあらかじめ定義する必要があります). 注意してほしいのはmain関数の中に記述されているawait asyncio.sleep()がuasyncioによる全体の実行時間となります. つまり先ほどのプログラムの実行時間は10秒となりますので, 実行結果から見るとも1秒間隔で10回出力されたことが見えます.
末尾
これでシンプルなマルチタスク処理ができました. プログラムはPeterさんのチュートリアルを一部参照して作りました. uasyncioは他の複雑な処理も提供しており, 詳細は[Github] (uasynciohttps://github.com/peterhinch/micropython-async/blob/master/v3/docs/TUTORIAL.md) に掲載されているので, 興味のある方は読み漁ろう.