Go の関数パフォーマンス

Page content

LuneScript は golang へのトランスコンパイルをサポートしている。

golang 対応の付加機能として、LuneScript には限定的なスレッド機能を提供している。

「限定的」の大きな理由の一つとして、 golang 向け LuneScript ランタイムのマルチスレッド対応問題がある。

golang 向け LuneScript ランタイム

golang 向け LuneScript ランタイムは、幾つか機能を持っている。 その機能の中には、次のものを含む。

  • and or 演算子の処理を実現するためのスタック。
  • lua ランタイム制御。

LuneScript は元々 Lua 向けのトランスコンパイラであり、 Lua はシングルスレッドの言語である。 そのため、 LuneScript の上記ランタイムもシングルスレッドを 想定した構成になっているため、そのままではマルチスレッドで利用できない。

シングルスレッド限定で良ければ、 マルチスレッドを考慮した作りに比べて簡単になるし、その分高速にもなる。

マルチスレッド対応

LuneScript ランタイムをマルチスレッド対応する際には、 次の 2 つの方法が考えられる。

  • ランタイムの複数インスタンス化
  • ランタイムの排他制御

ランタイムの複数インスタンス化

スレッド毎にランタイムをインスタンス化して管理する場合、 どのランタイムがどのスレッドのものかを管理する必要がある。

一方で、golang には go-routine の識別 ID がない。 つまり、 「必要な時に識別 ID からランタイムを取得する」 ということが 出来ないことになる。

cgo を利用すれば、 go-routine が動作している pthread ID を取得することは可能だが、 golang のタスクスケジューリングでは、 ある go-routine を実行する pthread が常に固定されている訳ではない。 つまり動的に取得した pthread ID は、 go-routine の ID にはならない。

ということは、 LuneScript ランタイム情報にアクセスするためには、 全ての関数にランタイム情報を渡していく必要がある。

ランタイムの排他制御

ランタイムの複数インスタンス化には、 全ての関数パラメータにランタイム情報の追加が必要になる。 これは、全ての関数でオーバーヘッドが追加になり、 当然プログラム全体がその分遅くなる。

そこで、ランタイムは複数インスタンス化せずに、 アクセスが必要な時だけ排他を掛けるケースを考える。

排他には次のケースがある。

  • mutex を使う
  • channel を使う

今回は両方検証する。

パファーマンス

golang の簡単なプログラムで、 複数インスタンス化したケースと、ランタイムの排他制御を実施したケースの パフォーマンスを測ってみた。

なお、実際に複数インスタンス化する訳ではなく、 関数に引数を追加するケースと、 排他制御を追加するケースとで、パフォーマンスを測っている。

結果以下となった。

引数に追加 <<<< mutex << channel

「引数に追加」が一番負荷が少なく、「channel」が一番負荷が高かった。

ただ「mutex」や「channel」の場合は、 必要な箇所だけに制御を追加すれば良いということを考えると、 「mutex」で対応するのが一番良いのかもしれない。

LuneScript のマルチスレッド対応は、「引数に追加」でいこうと思う。