Go言語で組み込みマイコンをプログラムできることを学んだのでGoしてます。マイブームってやつです。さて、Go言語には Goroutine という「簡易的な」並行処理の仕組みがあります。他の言語にもある Coroutine のGo版かと。時間シビアな目的には適さないような気もしますが、どのくらいな感じなの?
※「AT SAMの部屋」 投稿順indexはこちら
GoのGoroutineは、PythonのAsyncioみたいなもんという理解で良いですかね。RTOSでも似たような非プリエンプティブなスケジューリングも持つものが多く、過去XiaoボードでFreeRTOS使ってやってみています。
Seeduino Xiaoボード上で、TinyGo処理系でコンパイルしたオブジェクトを走らせて、Goroutineの「感触」をば掴みたいと思います。以下は公式のAPI解説ではないのですが、いつも参照させていただいている Go by Example のページです。例題コードが完結に説明されているので雰囲気掴みやすいです。
さて Coroutine は、並行処理といっても「自主的に制御権を返納」するとスーパバイザの方で「よきにスケジュール」してくれ、さも複数のルーチンが並行に走っているかのように見える仕組みです。今回はその「切り替え」をどのくらいのタイミングで起こすのが「現実的」なのかを実機で探ってみたいと思います。
ターゲット機Seeduino Xiaoは、SAMD21G18マイコン搭載、Arm Cortex-M0+のシングルコア@48MHzです。
実験用のGoソース
当然どのような処理をコルーチンとするかによって時間的なものは大きく変動する筈。今回は意味のある最小処理に近いと思われるGPIO端子のビットバンギング、LEDに適用すればLチカで見て行きたいと思います。
-
- 第1のGoroutineは外付け赤色LED接続端子をトグル
- 第2のGoroutineは外付け青色LED接続端子をトグル
- main()関数は2つのGoroutine起動後は、スリープしては起きるの繰り返し
一応LEDはついていますが、トグルレートは目にも止まらぬ速さです。そこで端子の状態をオシロで観察してみています。ソース全文が以下に。
package main import ( "machine" "time" ) func redLED() { led := machine.D2 led.Configure(machine.PinConfig{Mode: machine.PinOutput}) for { led.Low() time.Sleep(time.Millisecond * 10) led.High() time.Sleep(time.Millisecond * 10) } } func blueLED() { led := machine.D3 led.Configure(machine.PinConfig{Mode: machine.PinOutput}) for { led.Low() time.Sleep(time.Millisecond * 10) led.High() time.Sleep(time.Millisecond * 10) } } func main() { go redLED() go blueLED() for { time.Sleep(time.Millisecond * 1000) } }
実験結果
red/blueの両Goroutineのトグルレート50Hz(周期20ms)のつもりでソフトを設定した場合(上記コードそのまま)の出力波形が以下に。この速度ではほぼほぼ想定通りの結果が得られています。
つづいてハイ、ローの期間を以下のように変更(10分の1)した場合です。
time.Microsecond * 1000
トグルレートで500Hz(周期2ms)の想定。しかし、結果は以下のようでした。想定に近い周期で動作しているケース(ハイ期間が太い方)がある一方、どういう分けか不明な想定よりも早い期間で動作しているケース(ハイ期間が狭い)もあります。スケジューラのロジックとGoroutineの設定次第なんだと思いますが。。。全般を均してみれば、500Hz(2ms)に近いけれども微妙な感じ。
上がダメな感じなので期待持てないですが、ハイ、ローの期間をさらに短くしたケースです。
time.Microsecond * 100
トグルレートで5kHz(周期200μs)の想定ですが、以下のように上の結果より気持ち速い程度のレートに落ち着きました。上のケースより反って周期は安定。今回のような負荷であると、トグルレート675Hz、周期1.5msというのが、Goroutineのスケジューラ(Cortex-M0+@48MHz)のつり合いポイントなのですかね。知らんけど。
遅い方はともかく、素早い切り替え処理が必要になる場合は、精々上記の速さがXiaoでの処理の限界ですかね。定周期性がある程度必要になる(保証はできないと思います)ケースであれば数十Hzくらいのレートが現実的かと。
でもま、立派なRTOSなどなくてもさらっと並列処理がかけるので嬉しい。