Swoole との出会い
PHPカンファレンス福岡の前夜祭、及び afterhack にて、@uzulla さんが、
最近メールフォームかいてないメールフォーマーによる、ちょっとだけ変わった一応PHPのメールフォーム(?)のお話
という発表をされていました。
その中で、PHPのSwooleエクステンションのことについてお話されていました。
その話を聞いて興味を持ったので、今回ベンチマークを取ってみることにしました。
Swoole とは? という説明は上記の発表資料に書いてあるので割愛させていただきます。
上記資料には、
- 主にリクエストを処理するphp-fpmの代用としてSwoole
- タイマー
- シングルトン
- coroutine による非同期リクエスト
など盛り沢山ですが、
今回の話は、 coroutine による非同期リクエストだけ使いたい場合の話、
つまり、PHPで書いてあるコードの一部だけ非同期でリクエストを投げたい時の話です。
自分がパッと思いつくのは、
資料にも書かれているようにDNSを引く場合とか、SESにリクエスト投げつける場合とかです。
今までだと、Guzzle で実装していました。
環境
Docker on Mac 上に、 centos:latestイメージから立ち上げたコンテナで実験を行いました。
Swoole を使うときは、Mac上で直接ではなく、仮想環境上で行ったほうが良いらしいです。
Mac上よりもLinux上の方が処理が10倍速いとも、100倍速いとも。。。
ということで、
docker pull centos:latest
docker run --rm -it centos:latest /bin/bash
yum update -y && yum groupinstall "Development Tools" -y && yum install git wget curl vim -y
# https://webbibouroku.com/Blog/Article/centos-php7
yum install epel-release -y && rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
yum install --enablerepo=remi,remi-php72 php php-swoole -y
を行えば環境構築は完了です。
あとは、
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
composer require guzzlehttp/guzzle
を行うと、guzzle も使えるようになります。
実装
Guzzle を使った場合、Swoole を使った場合、普通に file_get_contentsを使った場合の3種類のコードを書いていきます。
Guzzle
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client();
$promises = [];
for ($i = 0; $i < 10; $i++) {
$promises[] = $client->requestAsync('GET', 'https://hogehogehogehoge.hoge/');
}
$responses = \GuzzleHttp\Promise\all($promises)->wait();
Swoole
<?php
for ($i=0; $i<10; $i++) {
go(function() {
$http = new \Swoole\Coroutine\Http\Client('hogehogehogehoge.hoge', 80);
$ret = $http->get('/');
});
}
file_get_contents
<?php
for($i=0; $i<10; $i++) {
file_get_contents('https://hogehogehogehoge.hoge/');
}
と、3種類のコードを書きました。
ベンチマーク結果
ベンチマークは、
time php hoge.php
を5回ずつ実行し、実行速度の平均値をベンチマーク結果としています。
結果は、
Guzzle | Swoole | file_get_contents | (参考) Guzzle 直列 | |
---|---|---|---|---|
real | 0m0.597s | 0m0.114s | 0m3.410s | 0m0.906s |
user | 0m0.112s | 0m0.024s | 0m0.154s | 0m0.064s |
sys | 0m0.102s | 0m0.006s | 0m0.024s | 0m0.066s |
となりました。
今回の結果だけでいくと、 Swoole が Guzzle の5倍ほど早いことになります。
また、Guzzle のコードは、Promise\all()->wait();
など、独特のコードを書く必要がありますが、
Swoole のコードは、割と直感的に書くことができます。
ということで、Swoole の有効性の片鱗が見えてきたので、
次は、CPU使用量やメモリ使用量などについても調べてみようと思います。
(今回は、サーバー立てるのめんどくさかった。)
もし問題なかったら、実戦投入も視野に入れていこうと思います。
余談
今回使ったSwooleのバージョンは、Swoole4 です。
Swoole の新機能に関しては、カジュアルに壊れてるらしい(@uzulla さん談)ので、
最新版のSwoole を使うときには注意が必要だそうです。
使ってみた感想
速い!
しかも、直感的に書けるので、割と重宝しそうです。
通常、APIのリクエスト数には上限があったりするので、
そのへんをどのように書けるかは少し調査が必要です。
あと、今回のメインテーマではないのですが、
Guzzle 直列と file_get_contents の間の実行時間の差が気になります。
機会があったら調べてみたいです。 (CPU使用量とかのほうが先。)