{
    "componentChunkName": "component---src-templates-blog-post-jsx",
    "path": "/post/benchmark-of-clearstatcache-in-php/",
    "result": {"data":{"site":{"siteMetadata":{"title":"WEB EGG","author":"Leko - CTO at Yuimedi"}},"markdownRemark":{"id":"7f85380c-5f37-580b-beaf-12de12e4decf","excerpt":"こんにちは。今回はPHPネタです。 PHPにはclearstatcacheという関数があります。 PHP…","html":"<p>こんにちは。今回はPHPネタです。</p>\n<p>PHPには<a href=\"http://php.net/manual/ja/function.clearstatcache.php\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">clearstatcache</a>という関数があります。</p>\n<blockquote>\n<p>PHPはパフォーマンス向上のために それらの関数の戻り値をキャッシュします。しかし、ケースによっては、 キャッシュされた情報を消去したい場合もあるでしょう。 例えば、一つのスクリプト上で同じファイルが何度もチェックされ、 そのファイルが変更されたり削除されたりする可能性がある場合、 ステータスキャッシュを消去しなければならないと感じるでしょう。 このようなケースでは、clearstatcache()を使用することで ファイルの情報に関してPHPが持っているキャッシュをクリアできます。<br>\n— <a href=\"http://php.net/manual/ja/function.clearstatcache.php\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">PHP: clearstatcache – Manual</a></p>\n</blockquote>\n<p>この機能はドキュメント見る限り割と古くから導入されてるそうですが、PHP 5.1でバグってました。<br>\nそれは後述するとして、 <strong>このバグを引き換えに得られる性能</strong> はどんなもんなのさ？ を計測してみました。</p>\n<!--more-->\n<h2 id=\"はじめに\" style=\"position:relative;\"><a href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\" aria-label=\"はじめに permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>はじめに</h2>\n<p><code>clearstatcache</code>によるバグは確認した限りではPHP 5.1にて発生しました。<br>\nPHP 5.5, 5.6においては修正されて予期したとおりの挙動になっていました。<br>\n5.2, 5.3, 5.4では確認をしていないため、その間のいつバグが治ったのかは未確認です。</p>\n<h2 id=\"clearstatcache周りで起きるバグとは\" style=\"position:relative;\"><a href=\"#clearstatcache%E5%91%A8%E3%82%8A%E3%81%A7%E8%B5%B7%E3%81%8D%E3%82%8B%E3%83%90%E3%82%B0%E3%81%A8%E3%81%AF\" aria-label=\"clearstatcache周りで起きるバグとは permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>clearstatcache周りで起きるバグとは</h2>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token php language-php\"><span class=\"token delimiter important\">&lt;?php</span>\n\n<span class=\"token variable\">$file</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'なんか存在するファイル'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token function\">file_exists</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$file</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// true, 当然の結果</span>\n<span class=\"token function\">unlink</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$file</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token function\">file_exists</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$file</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// true, ！？</span></span></code></pre></div>\n<p>\n  古いPHPでこのコードを動かすとコメントのとおりになります。<br />\n  ユニットテストで意図的にファイルを消すようなテストを書いていたら思い切りハマりました。<br />\n  諸々調べてみると<a href=\"http://php.net/manual/ja/function.clearstatcache.php\">clearstatcache</a>という関数に行き着きました。\n</p>\n<p>\n  まずはclearstatcacheのドキュメントを読んでみます。<br />\n  ※まず前提として、 <strong>明言されてない仕様</strong> が隠されています。\n</p>\n<blockquote>\n  <p>\n    PHP は存在しないファイルについての情報はキャッシュしないことにも 注意してください。もし存在しないファイルに対して file_exists() をコールする場合、ファイルを作成するまで この関数は FALSE を返します。もしファイルを作成した場合、 たとえファイルを削除したとしても TRUE を返します。 しかし、unlink() はキャッシュを自動的にクリアします。<br />\n      &mdash; <a href=\"http://php.net/manual/ja/function.clearstatcache.php\">PHP: clearstatcache - Manual</a>\n  </p>  \n</blockquote>\n<p>\n  \"たとえファイルを削除したとしても TRUE を返します\"って変だと思わないんですかね・・・<br />\n  ファイルを削除した場合キャッシュを開放とか内部実装してくれよ・・・意味わからん・・・<br />\n  細かいバージョンまではわかりませんが、古いPHPにおいてはこの機能のせいでバグっています。\n</p>\n<p>\n  しかし、PHP5.5以上で確認してみると、rmdirでもキャッシュが消えてました。<br />\n  環境依存なのかバージョン依存なのか、詳しく追えていません。\n</p>\n<h2 id=\"ベンチマークを取ってみる\" style=\"position:relative;\"><a href=\"#%E3%83%99%E3%83%B3%E3%83%81%E3%83%9E%E3%83%BC%E3%82%AF%E3%82%92%E5%8F%96%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B\" aria-label=\"ベンチマークを取ってみる permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>ベンチマークを取ってみる</h2>\n<p>\n  期待通りの挙動を犠牲にしてまで手に入れたパフォーマンスとはどんなもんなのか。いざ実測。<br />\n  ベンチマークに使用したコードはこんな感じです。\n</p>\n<p>\n  <code>call_with_cache</code>, <code>call_nocache</code>が比較処理です。<br />\n  違いは毎回<code>clearstatcache</code>してから処理を呼ぶか、clearstatcacheしないか。\n</p>\n<p>\n  先述の通りファイルが存在しない場合はキャッシュされないそうなので、テストケースから除外。<br />\n  確実に存在するファイルパスである自分自身を参照しています。\n</p>\n<p>\n  テスト対象はPHPのドキュメントを信じました。\n</p>\n<blockquote>\n  <p>\n    影響を受ける関数を以下に示します。 stat(), lstat(), file_exists(), is_writable(), is_readable(), is_executable(), is_file(), is_dir(), is_link(), filectime(), fileatime(), filemtime(), fileinode(), filegroup(), fileowner(), filesize(), filetype(), および fileperms().<br />\n      &mdash; <a href=\"http://php.net/manual/ja/function.clearstatcache.php\">PHP: clearstatcache - Manual</a>\n  </p>  \n</blockquote>\n<p>\n  この機能に影響するiniの設定は以下のとおりです。\n</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ php -i | grep realpath_cache_\nrealpath_cache_size => 16K => 16K\nrealpath_cache_ttl => 120 => 120</code></pre></div>\n<p>\n  で、肝心のベンチマーク結果は以下のとおりです。\n</p>\n<p><img src=\"https://docs.google.com/spreadsheets/d/1UU0mM1_OVmC-vajpICnqMV0ygtcyXKqmqZiHxAo6IyQ/pubchart?oid=362709528&#x26;format=image\" alt=\"benchmark\"></p>\n<p>\n  <strong>全般的にclearstatcacheしたほうが早い</strong> というわけのわからない結果になりました。<br />\n  だったらこの機能いらないじゃん！なんだそれ！！\n</p>\n<p>\n  試しにiniの設定を書き換えリアルパスキャッシュを無効化したり、逆に<code>realpath_cache_size</code>を16Kから16Mに増やして実行してみたところ、誤差の範囲内の違いしか出ませんでした。<br />\n  <strong>なんだそれ！！！</strong>\n</p>\n<h2 id=\"まとめ\" style=\"position:relative;\"><a href=\"#%E3%81%BE%E3%81%A8%E3%82%81\" aria-label=\"まとめ permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>まとめ</h2>\n<p>\n  私の環境でベンチマーク取った限りでは、完全に無駄というかむしろ邪魔な機能という結果になりました。<br />\n  どんな歴史的経緯があるのかまでは調べてませんが、なぜこんな機能作ったんだろう。\n</p>\n<p>\n  古いPHPではバグってるし、新しいPHPでも性能に寄与してないし。<br />\n  久々に予想を覆す、ベンチマーク取ってよかったと感じる計測でした。\n</p>","timeToRead":5,"frontmatter":{"title":"PHPのclearstatcacheのベンチマークを取ってみた。むしろ遅かった。","tags":["PHP"],"date":"October 11, 2016","featuredImage":null}}},"pageContext":{"slug":"/benchmark-of-clearstatcache-in-php/","previous":{"fields":{"slug":"/learn-makefile/"},"frontmatter":{"title":"Makefile初めて触った。めっちゃ簡単だった","tags":["CLI"]}},"next":{"fields":{"slug":"/we-should-use-variable-get-to-admin-or-not/"},"frontmatter":{"title":"Drupal7で指定したユーザが管理者ロールか否かを判断したいときはvariable_getを使いましょう","tags":["Drupal","PHP"]}}}},
    "staticQueryHashes": ["2585454260","2954598359"]}