クラウド時代のWebアプリケーション・スマートフォンアプリを開発・運用する会社です。 03-4577-8680 03-6673-4950

PHPExcelが遅い場合

2013-09-08

ネタバレ:犯人は ヤス xdebug。

PHPExcelというPHPライブラリがありまして、PHPでシンプルなExcelを生成するのに便利なので、何かと利用しているわけです。

#「シンプルな」というのはどういうことかと言うと、
#既存のExcelファイルを開いて操作することも可能ではあるのですが、
#いわゆる「Excel方眼紙」や、図表が入っている場合には、ほぼ再現できないためです。

さて、このPHPExcel、「遅い」ともっぱらの評判です。

しかし。

手元の環境で、
・6×50行
・150シート
というデータで生成しているのですが、これが10分以上かかる(!)というのは、さすがに何かおかしいと思うわけです。

検索した結果、高速化させる方法としていくつか上げられている答えが:
・シートをコピーしないようにする
・罫線を1セルづつ引かない(まとめて引く)
・ループが終わったらメモリを開放する
はい。やってみました。
細かいことは省きますが、最終的に30秒くらい早くなりました。
……30秒に、ならよかったんですが。

さてではもう少しスコープを広げて検索してみます。
どうやらPHPExcelで最も多い質問は、メモリフルエラーのようですね。

というわけで memory_get_usage() と microtime() を入れてトレースしてみたのですが、 microtime() どころか time() で間に合うくらいまんべんなく時間がかかっています。
メモリの使用量は、さほど猛烈な量というわけでもありません。
しかし、topコマンドを走らせながら結果を見て見ると、CPU使用率が振り切っています。
普通に考えるとこれは、
・計算量がめちゃめちゃすごい
・何かファイルI/Oがすごい
ということだろうと推測できます。

計算量がすごいことになってるというのであればまたこれはしょうがないんですが、
まんべんなく時間がかかってるのはちょっと納得がいかないわけです。
納得はいかないものの、時間がなかったのでここでいったん放置しました。

・・・・・・

さて、2週間ほど後、全く関係ない謎事態が発生しました。
いつのまにか、HDの残り容量が全然無いのです。
とりあえずduコマンドで原因を探すと、/var/tmp/にcachegrind.out.*というファイルが150GB分存在しています。
cachegrind.out.*とはなんぞ、と検索してみると、これはxdebugが生成しているということです。
じゃー消していいや。わーい150GB空いたよー。

……xdebugが……生成する?……ファイルI/O……?

ということでしょうもない茶番をはさみましたが、xdebugがcachegrind.out.*を書いてるのが原因じゃないか?ということで、xdebugをOffにしてみることにしました。

で、そもそもなんでxdebugが入っているかというと、phpuntを入れているから(phpunitのコードカバレッジ機能に必須)で、PHPExcel走らせる時だけOffにできないのかなと思ったのですが、これもあれこれ試してみた結果、今回関連している個所はiniに書かないと効果が無いようなので、とりあえず、
xdebug.profiler_enable=0
にしておきます。

結果、あの10分かかっていたPHPExcelでのファイル生成が、なんと、
80秒
で終わるようになりました。
10分間、動いてたのはほとんどxdebugだったということになるわけですなー……

#その後、「遅いなー」と思っていた処理がことごとく速くなりました