一年近く、組み込みLinuxでのユーザープロセスをgolangで書くことを試していたのですが、これはいける! という感触を持ちました。
仲間を増やしたいと思うので、ここにその情報を紹介します。
#何をしたか
既存の製品をベースにして、新機能の実装をGolangで書いてみました。
既存の部分はCで書いてあります。Golangで書いた新機能部分は別プロセスになっています。
既存部分とのやりとりは場面によって以下を使い分けました。
- cgoによる関数呼び出し
- UNIXドメインソケットの通信
- シグナル
Golangで書いた部分には以下の要素を含みます。
- UARTやi2cで接続されたセンサーからデータを受け取る
- インターネット上のWebサービスのAPIを使用する
- 2Dグラフィックスの描画 (cairoを使用)
最大性能を目指すよりも、十分な性能を手早く形にすることを重視しました。
#Golangでよかったところ
(私の感想です。)
-
mmapやioctlのシステムコールを扱うことができる。これで低レベルの部分までcgoに頼らずに直接Golangで記述できた。
-
goroutineを使った非同期処理が非常に簡潔に書ける。
-
GCによるメモリ管理があること。GCによる遅延は問題にはならなかった。
-
PC Linuxで部分的に動作確認したコードを実機(ARM Linux)に持って行くのが楽であった。
-
シミュレータやデータ変換などの周辺ツールもGolangで書くのが楽であった。
-
意味不明のクラッシュが発生することがなく、デバッガは不要だった。(例えば、sliceの範囲を超えたときにはpanicになってスタックトレースが出力される)
-
cgoでCの関数を呼ぶのも容易。
-
有用なライブラリが豊富。
-
既存ライブラリのGolang bindingも多い。(cairoのgo bindingを使用した)
#Golangで困ったところ
うまいやり方がわからずに迷ったことはありましたが、そんなに困ったことはありませんでした。
強いてあげれば
- 実行ファイルのサイズが大きい。
これの対策を別の記事に書きました。
Golangの実行ファイルを複数まとめてトータルのファイルサイズを減らす工夫(busybox方式)
#実践的な情報
組み込みLinuxで使う上で必要だったことに関して別に記事を書きました。
Golangから物理メモリを読み書きする
Golangでioctlのシステムコールを使う
GolangでGPIOの割り込み通知を受け取る
GolangのプロセスをFIFO priorityにセットする
Golangでシリアルポート(UART)を使う
GolangでBLE (Bluetooth Low Enagy)を使う
Golangでlogのタイムスタンプをマイクロ秒単位にする方法
Golangで周期的に実行するときのパターン
#というわけで
これからも積極的にGolangを使っていきたいと思います。
私はGCのある言語は好き派。大昔の携帯Javaの頃はGCでの動作停止時間がかなり気になったものだけど、現在のgolangでは私の用途ではGCの停止時間はほとんど感じられないほど小さい。
— 組み込みの人。 (@tetsu_koba) 2018年1月17日
GolangはOS無しのマイコンでは動かせない。(実験的なプロジェクトはあるみたいだけど。) LinuxがあればOK。ラズパイとかナノパイとか。
— 組み込みの人。 (@tetsu_koba) 2018年1月17日
OS無し(ベアメタル)の環境に何かの言語のランタイムを実装するのって難しくて、誰にでもできることじゃない。Golangの場合はLinuxカーネル(あるはBSD)さえあれば、「ランタイムを実装する」手間が一切無いのが好き。
— 組み込みの人。 (@tetsu_koba) 2018年1月17日
#追記 2018.1.31
参考になりそうなページ
https://github.com/rakyll/go-hardware
http://embd.kidoman.io/
#追記 2022.4.12
こちらの記事に講演した時のスライドとビデオがあります。
「組み込みLinuxでのGolangのススメ」を講演しました