libffi を使って PHP から Go の関数を呼び出して速度を計測しました。
参考記事
RubyからGoの関数をつかう → はやい の記事に触発されて書きました。
システム要件
- PHP 7.0
- Go 1.5
libffi のインストール
Mac OS X の homebrew では次のコマンドでインストールできます。
brew install libffi
MFFI のインストール
PHP 7.0 であれば、MFFI を使うことができます。
git clone https://github.com/mgdm/MFFI.git
cd MFFI
phpize
./configure
make
make install
echo extension=mffi.so > /usr/local/etc/php/7.0/conf.d/ext-mffi.ini
mffi エクステンションが読み込まれているか確認しましょう。
php -m | grep mffi
うまく読み込まれていない場合、設定ファイルを確認してみましょう。
php --ini
Go のコードから共有ライブラリ (so) を生成する
フィボナッチ数列を再帰関数で定義してみましょう。
fib.go
package main
import "C"
//export fib
func fib(n uint) uint {
if n < 2 {
return n
}
return fib(n-1) + fib(n-2)
}
func main() {}
go build
コマンドで so ファイルを生成しましょう。
go build -buildmode=c-shared -o fib.so fib.go
PHP から呼び出す
PHP でフィボナッチ数列を再帰関数で定義してみましょう。PHP 7.0 から引数と戻り値に int
の型を宣言できるようになりました。
fib.php
function fib(int $n): int {
return $n < 2 ? $n : fib($n - 1) + fib($n - 2);
}
echo fib(10), PHP_EOL;
今度は so ファイルを読み込んで、go の関数を呼び出してみましょう。MFFI エクステンションのチュートリアルはこちらをご参照ください。
go-fib.php
use MFFI\Type;
$library = new MFFI\Library('fib.so');
$fib = $library->bind('fib', [Type::TYPE_INT], Type::TYPE_INT);
echo $fib(10), PHP_EOL;
C 言語から呼び出す
せっかくなので、C 言語からも呼び出してみましょう。
fib.c
#include <stdio.h>
#include "fib.h"
int main(void) {
printf("%llu\n", fib(10));
return 0;
}
ビルドして実行してみましょう。
gcc -pthread fib.c fib.so -o fib
./fib
簡易ベンチマーク
n を10ごと増やしてベンチマークをとってみました。n = 20 まではほとんど代わらず、n = 40 で急激に大きな速度の差が生まれるようになりました。
n = 10
time php fib.php
55
real 0m0.054s
user 0m0.037s
sys 0m0.012s
time php go-fib.php
55
real 0m0.060s
user 0m0.038s
sys 0m0.017s
n = 20
time php fib.php
6765
real 0m0.060s
user 0m0.042s
sys 0m0.013s
time php go-fib.php
6765
real 0m0.059s
user 0m0.036s
sys 0m0.017s
n = 30
time php fib.php
832040
real 0m0.365s
user 0m0.346s
sys 0m0.013s
time php go-fib.php
832040
real 0m0.066s
user 0m0.045s
sys 0m0.016s
n = 40
time php fib.php
102334155
real 0m39.840s
user 0m39.177s
sys 0m0.145s
time php go-fib.php
102334155
real 0m1.237s
user 0m1.209s
sys 0m0.020s