綺麗に死ぬITエンジニア

PHP 7系からは高速array_diff関数は必要ない

2016-11-18

PHP 5.6以前では、遅かった配列処理系の関数も、PHP 7以降ではかなり高速化されています。

PHP 5.6以前で、array_diff関数が遅く、独自の高速化array_diff関数を使っていた方も多いのではないでしょうか。

以下のような関数です。

高速化array_diff関数

<?php

function fast_array_diff()
{
  return array_flip(call_user_func_array('array_diff_key', array_map('array_flip', func_get_args())));
}

上記のfast_array_diff関数は、$array === array_flip(array_flip($array))が成立するような配列にのみ適用できる、array_diffを高速化した関数です。つまり、以下の場合のみ利用することができます。

  • 配列の全ての要素が「整数(int)」or「10進数値形式ではない文字列(string)」からなる
  • 配列の全ての要素がユニークである(重複しない)

上記は、array_flip関数を用いているがための特性です。

PHP 5.6以前では、この条件下であれば、これを用いてarray_diff関数をかなり高速化することができました。

ベンチマーク

実際に、こちらのプログラムを用いて、ベンチマークを行ってみます。

ランダムに並び替えられた15万の要素(厳密には150,001要素だが、以下省略)を持つ配列と、ランダムに並び替えられた10万の要素を持つ配列で、array_diff関数を実行し、時間を計測するプログラムです。

array_diff.phpは通常のarray_diff関数を、fast_array_diff.phpは独自の高速化array_diff関数fast_array_diff()を利用します。

PHP 5.6

PHP 5.6環境における結果が、以下のとおりです。

$ php -v
PHP 5.6.25 (cli) (built: Sep  6 2016 16:37:16) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
$ php array_diff.php
処理時間: 1.0187411308289秒
$ php fast_array_diff.php
処理時間: 0.1289598941803秒

array_diff.phpは処理に1秒以上かかっており、fast_array_diff.phpの方がかなり早く処理できることがわかると思います。

PHP 7.0

ところが、PHP 7.0における結果は、以下のようになります。

$ php -v
PHP 7.0.12 (cli) (built: Oct 14 2016 09:56:59) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
$ php array_diff.php
処理時間: 0.039209127426147秒
$ php fast_array_diff.php
処理時間: 0.033622026443481秒

そもそもの処理時間が5.6に比べ、かなり短くなっていることに加え、若干fast_array_diff.phpの方が早いですが、両者の処理時間の差はほとんど誤差のレベルまで縮んでいます。

ここまで処理時間の差が縮んでしまえば、fast_array_diff関数が特定の条件下でしか利用できないデメリットを考えると、もうほとんどのケースにおいてfast_array_diff関数は利用しなくてもよいと考えて問題ないでしょう。

引数3つ時のベンチマーク

念のため、引数が3つの場合のベンチマークも行っておきます。

実行するプログラムは、こちらです。

ランダムに並び替えられた15万の要素を持つ配列と、ランダムに並び替えられた10万の要素を持つ配列2つで、array_diff関数を実行し、時間を計測するプログラムです。

PHP 5.6

PHP 5.6環境における結果は、以下のとおりです。

$ php -v
PHP 5.6.25 (cli) (built: Sep  6 2016 16:37:16) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
$ php array_diff.php
処理時間: 1.4854810237885秒
$ php fast_array_diff.php
処理時間: 0.17208290100098秒

1回目と同様、fast_array_diff.phpの方がかなり早いです。

PHP 7.0

PHP 7.0における結果は、以下のとおりです。

$ php -v
PHP 7.0.12 (cli) (built: Oct 14 2016 09:56:59) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
$ php array_diff.php
処理時間: 0.059709787368774秒
$ php fast_array_diff.php
処理時間: 0.034765005111694秒

引数を3つにすると、2つのときよりも処理時間の差が開きました。ここにきて盛り返すfast_array_diff.php

しかし、十数万単位の配列操作で0.03秒程度の差であれば、やはりPHP 7.0においてfast_array_diff関数を採用するメリットは少なそうです。

引数5つ時のベンチマーク

引数3つでPHP 7.0の処理時間の差が開いてしまったので、念のため、5つでもベンチマーク。

例によって、実行するプログラムは、こちらです。

PHP 5.6

PHP 5.6環境における結果は、以下のとおりです。

$ php -v
PHP 5.6.25 (cli) (built: Sep  6 2016 16:37:16) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
$ php array_diff.php
処理時間: 2.1798341274261秒
$ php fast_array_diff.php
処理時間: 0.20542788505554秒

これまでと同様にfast_array_diff.phpの方がかなり早いです。こちらもPHP 7.0と同様に、だんだんと処理時間に差が開いてきました。

PHP 7.0

PHP 7.0における結果は、以下のとおりです。

$ php -v
PHP 7.0.12 (cli) (built: Oct 14 2016 09:56:59) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
$ php array_diff.php
処理時間: 0.097110986709595秒
$ php fast_array_diff.php
処理時間: 0.03524112701416秒

またも、差が開きました。

fast_array_diff.phpに関していえば、引数が増えても処理速度が全然増えません。データ量にあまり依存しないのは、この関数のメリットでしょうか。

まとめ

PHP 7以降の環境では、一般的な用途では、高速化array_diff関数は必要ないです。

しかしながら、配列処理の遅延が命取りになるような環境でなおかつ、array_diff()に大量に引数を与えるような利用をする場合は、利用するのもアリです。

普通は、もう利用しなくていいでしょう。

まだ、PHP 5系で頑張っている方々は、7系の導入を検討してみてはいかがでしょうか。

筆者について

フリーランスエンジニアとして活動している、「もりやませーた」です。

筆者のTwitterはこちら。記事に関するご意見等はTwitterの方へお寄せください。

その他業務に関するお問い合わせは、こちらのページをご覧ください。

PHP