13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PHP7.4の新機能、FFIでGoを使ってみた

Last updated at Posted at 2019-12-05

PHP7.4がリリースされた

今回のアップデートも目まぐるしい機能が多く追加されました
機能の紹介は既にあるたくさんの記事にお任せするとして、個人的に気になっていた新機能 FFIを試してみます

FFIとは

Foreign Function Interface の略でPHPで別の言語を動かせる機能です
Cなどで実装した共有ライブラリを読み込んで、利用することができます
メリットとしては実行速度が速くなることが大きいかと思われます

FFIでGoを利用する

本題です
Goを利用するにはGoで共有ライブラリを実装する必要があります

何故Goを利用するのか

Cより簡単だから

Goで共有ライブラリを作るには

  • packageをmainにする
  • main関数が必要
  • exportする関数に //export [function name] のコメントを書く
  • ビルド時は -buildmode=c-shared を付ける

今回はフィボナッチ数を計算するプログラムを用意しました
再帰を使っていて数が大きくなるほど計算に時間がかかるサンプルです

package main

import "C"

//export calcFibonacci
func calcFibonacci(i uint) uint {
    if i < 2 {
        return i
    }

    return calcFibonacci(i - 1) + calcFibonacci(i - 2)
}

func main() {}

ビルド

説明通り -buildmode=c-shared を付けてビルドします
出力ファイル名は、Windowsの場合は *.dll 、macOSでは *.dylib 、Linuxでは *.so でしょうか
今回はmacOSを使っているので、 fibonacci.dylib というファイル名を指定しました

ビルドを済ませると指定したファイル名のバイナリと同じ名前の *.h ファイルが生成されているはずです
このヘッダーファイルを用いることで他のプログラムから利用することができます
(今回はこのヘッダーファイルを利用しない方法で説明します)

PHPからFFIでGoを利用する

準備が整ったのでいよいよFFIを利用します

cdef関数を利用します
一つ目の引数にC形式での関数定義
二つ目の引数に共有ライブラリへのパスを指定します

$ffi = FFI::cdef(
    'extern unsigned int calcFibonacci(unsigned int p0);',
    '[PATH]/fibonacci.dylib'
);

あとはこのように呼び出すことができます

echo($ffi->calcFibonacci(10)); // 55

以上がFFIからGoを利用する方法です
では、続いてどれだけ実行速度に差が出るか比較してみます

FFIでPHPはどれだけ速くなるか

以下のような検証用プログラムを作成しました
FFIとPHPそれぞれでフィボナッチ数列を40番目まで求めるプログラムです
実行はCLIから行いました

const COUNT = 40;

$ffi = FFI::cdef(
    'extern unsigned int calcFibonacci(unsigned int p0);',
    '[PATH]/fibonacci.dylib'
);

// 比較対象のPHP実装サンプル
function calcFibonacci(int $i): int {
    if ($i < 2) {
        return $i;
    }

    return calcFibonacci($i - 1) + calcFibonacci($i - 2);
}

// Go(FFI)実装の実行速度計測
$startTime = microtime(true);
for($i = 1; $i <= COUNT; $i++) {
    $ffi->calcFibonacci($i);
}
$time = microtime(true) - $startTime;
echo "Go(FFI): {$time}\n";

// PHP実装の実行速度計測
$startTime = microtime(true);
for($i = 1; $i <= COUNT; $i++) {
    calcFibonacci($i);
}
$time = microtime(true) - $startTime;
echo "PHP: {$time}\n";

結果

Go(FFI): 1.5760109424591 秒
PHP: 33.616943836212 秒

かなり大きな差が出ていると思います
PHPで重い処理を行う場合に、FFIはかなり強みになると感じました

13
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?