AT SAMの部屋(4) XiaoでもGo!Goroutineで並行処理、どこまでいけそう?

Joseph Halfmoon

Go言語で組み込みマイコンをプログラムできることを学んだのでGoしてます。マイブームってやつです。さて、Go言語には Goroutine という「簡易的な」並行処理の仕組みがあります。他の言語にもある Coroutine のGo版かと。時間シビアな目的には適さないような気もしますが、どのくらいな感じなの?

GoのGoroutineは、PythonのAsyncioみたいなもんという理解で良いですかね。RTOSでも似たような非プリエンプティブなスケジューリングも持つものが多く、過去XiaoボードでFreeRTOS使ってやってみています

Seeduino Xiaoボード上で、TinyGo処理系でコンパイルしたオブジェクトを走らせて、Goroutineの「感触」をば掴みたいと思います。以下は公式のAPI解説ではないのですが、いつも参照させていただいている Go by Example のページです。例題コードが完結に説明されているので雰囲気掴みやすいです。

Go by Example: Goroutines

さて 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)のつもりでソフトを設定した場合(上記コードそのまま)の出力波形が以下に。この速度ではほぼほぼ想定通りの結果が得られています。

Duration10ms

つづいてハイ、ローの期間を以下のように変更(10分の1)した場合です。

time.Microsecond * 1000

トグルレートで500Hz(周期2ms)の想定。しかし、結果は以下のようでした。想定に近い周期で動作しているケース(ハイ期間が太い方)がある一方、どういう分けか不明な想定よりも早い期間で動作しているケース(ハイ期間が狭い)もあります。スケジューラのロジックとGoroutineの設定次第なんだと思いますが。。。全般を均してみれば、500Hz(2ms)に近いけれども微妙な感じ。

Duration1000us

上がダメな感じなので期待持てないですが、ハイ、ローの期間をさらに短くしたケースです。

time.Microsecond * 100

トグルレートで5kHz(周期200μs)の想定ですが、以下のように上の結果より気持ち速い程度のレートに落ち着きました。上のケースより反って周期は安定。今回のような負荷であると、トグルレート675Hz、周期1.5msというのが、Goroutineのスケジューラ(Cortex-M0+@48MHz)のつり合いポイントなのですかね。知らんけど。

Duration100us

遅い方はともかく、素早い切り替え処理が必要になる場合は、精々上記の速さがXiaoでの処理の限界ですかね。定周期性がある程度必要になる(保証はできないと思います)ケースであれば数十Hzくらいのレートが現実的かと。

でもま、立派なRTOSなどなくてもさらっと並列処理がかけるので嬉しい。

AT SAMの部屋(3) XiaoでもGo!TinyGoでXiaoの吉例Lチカ へ戻る

AT SAMの部屋(5) XiaoでもGo!秋月AQM1602をTinyGoで制御してみる へ進む