概要
早見表
定数 | 意味 |
---|---|
CURLOPT_MAXCONNECTS (PHP5.5以降) |
curl_exec でキャッシュされる非アクティブなTCPコネクション最大数 |
CURLMOPT_MAXCONNECTS (PHP5.5以降) |
curl_multi_exec でキャッシュされる非アクティブなTCPコネクション最大数 |
CURLMOPT_MAX_TOTAL_CONNECTIONS (PHP7.0.7以降) |
curl_multi_exec で使用される**アクティブな**TCPコネクション最大数 |
- 非アクティブ
→ これをいじったところで何も嬉しくない場合がほとんど - アクティブ
→ これの数を制御したい!!!
従来は…
TCPコネクションを増やし過ぎないようにPHP側でプールサイズを制御する必要があった
- 実装が面倒
- この手法は
CURLMOPT_PIPELINING
によるHTTP/1.1のパイプライン化・HTTP/2のマルチプレクサの設定と相性が最悪- 実際にこれらのグループ化が行われたかどうかをPHP側から知るすべが無い
HTTP/1.1のパイプライン化を使う場合の問題
- 確立直後のTCPコネクションではパイプライン化を行ってはならない
- TCPコネクションがKeep-Aliveであることを確認してから初めて許可される
これはつらい.直接パイプライン化適用の有無を知る手段が無いため,いま当該サーバとの間のTCPコネクションが生きているかどうかを何とかして確認する必要があるが…実装は複雑になりそう.
HTTP/2のマルチプレクサを使う場合の問題
- 相手がHTTP/2に対応しているかを事前に知っておかなければならない
- HTTP/1.1にフォールバックされる可能性がある
こっちは相手サーバが限定される場合はまだ何とかなりそう…?
今後は…
PHP7.0.7以降はプールサイズの管理をlibcurlに丸投げできて最高
コードで理解する CURLMOPT_MAX_TOTAL_CONNECTIONS
コンストラクタでプールサイズを指定して,こんなコードを動かせるようにPoolクラスを作りたい.
$pool = new Pool(5);
for ($i = 0; $i < 10; ++$i) {
$ch = curl_init('example.com');
$pool->add($ch);
}
$pool->exec();
PHP7.0.6以前
class Pool
{
protected $mh;
protected $size;
protected $added = [];
protected $queue = [];
public function __construct(int $size)
{
$this->mh = curl_multi_init();
$this->size = $size;
}
public function add($ch)
{
if (count($this->added) < $this->size) {
curl_multi_add_handle($this->mh, $ch);
$this->added[(int)$ch] = $ch;
} else {
$this->queue[] = $ch;
}
}
public function exec()
{
curl_multi_exec($this->mh, $running);
do {
if (curl_multi_select($this->mh) === -1) {
usleep(2500);
continue;
}
curl_multi_exec($this->mh, $running);
$this->read();
} while ($this->shift() || $running);
}
protected function read()
{
while ($info = curl_multi_info_read($this->mh)) {
unset($this->added[(int)$info['handle']]);
}
}
protected function shift()
{
while (count($this->added) < $size) {
$ch = array_shift($this->queue);
curl_multi_add_handle($this->mh, $ch);
$this->added[(int)$ch] = $ch;
}
return isset($ch);
}
}
オエエエエエエエエエ
PHP7.0.7以降
class Pool
{
protected $mh;
public function __construct(int $size)
{
$this->mh = curl_multi_init();
curl_multi_setopt($this->mh, CURLMOPT_MAX_TOTAL_CONNECTIONS, $size);
curl_multi_setopt($this->mh, CURLMOPT_PIPELINING, 3);
}
public function add($ch)
{
curl_multi_add_handle($this->mh, $ch);
}
public function exec()
{
curl_multi_exec($this->mh, $running);
do {
if (curl_multi_select($this->mh) === -1) {
usleep(2500);
continue;
}
curl_multi_exec($this->mh, $running);
} while ($running);
}
}
イケメン!!!!しかもパイプラインやマルチプレクサも軽々扱えるなんて完璧すぎる!!!
補足
curl_multi_init
で作成したリソースを破棄すると**「パイプラインが可能である」と許可しているメモが吹っ飛ぶ.**要注意.