Monthly Archives: 1月 2015

集計プログラムにおける言語速度比較(PHP Perl Java Go)

(プログラムにバグがあったので計測やりなおして再投稿)

Perlでガリガリと解析しているのですが解析速度がどうしても遅い。単発作業ならまだしも、定期的に依頼が来るとプログラムの遅さが重なり結構な時間が掛かってしまいます。

そこで他の言語を使い速度比較。Go、PHP、Javaで似たようなコードを書いて時間計測でベンチマークを取ります。

ただ最初にお断りしておくと、昨今の流行りのデータマイニングではなく導線比較や継続集計(analysis)といったアクセス解析的なプログラムで、且つ一部分での比較となります。

元のPerlプログラム(比較用に遅い部分を切り出し)。

データベースAから取得したuser_idとデータベースBの入会データをマッチさせて、マッチした情報を一時テーブルに入れるだけ。最適化も何もしていないので突っ込みどころの多いコードですが、実際の集計だと手直しや仕様変更や概念違いによる書き直しが多いので、面倒な記述はなかなか出来ないのです(bind_columns使えとか1行insertにしろとかthreadsで投げろとか聞こえてきそうですが)。

で、これを他の言語に書き換えて時間を測ります。PHPとJavaとGo言語のプログラムは一番下に記します。

速度予想

Go言語>Java>PHP>Perlの順で早いだろうと予想(PHPとPerlは誤差程度)。もしくはほぼ誤差で変わらず。MySQLやI/O負荷がボトルネックになりあまり差がでない可能性も考えました。一抹の不安はJavaがソケット接続出来ずにポート接続になること。

結果

CPU:Pentium G3258  SSD:M5Pro

timeコマンドで計測

Go PHP Perl Java
real    0m13.598s
user    0m1.054s
sys    0m1.287s
real 0m10.412s
user 0m0.799s
sys 0m0.862s
real 0m9.709s
user 0m1.694s
sys 0m0.452s
real 0m17.294s
user 0m6.189s
sys 0m1.124s

Perl>PHP>Go言語>Java

Perl速い。Java遅い。

Javaの遅さは後ほど考察。何も考えずにダラダラ書くと世間で言われている通り遅くなります。

ここまでの感想

Goが予想に反して速くない。ただ改善の余地はありそう。PHPとPerlはインタプリタ言語らしくほぼ変わらず。たぶんRubyやPythonも(巷のベンチマーク結果から勘案して)それほど変わらないでしょう。Javaは困った。

ソケット接続からポート接続に変更

Javaは言語仕様でソケット接続がサポートされていないらしい。よって他の言語もポート接続に変更して再実行。

Go

PHP

Perl

ポート接続の結果

Go PHP Perl Java
real    0m15.809s
user    0m1.201s
sys    0m1.896s
real 0m12.665s
user 0m0.947s
sys 0m1.492s
real 0m11.819s
user 0m2.068s
sys 0m0.883s
real 0m17.294s
user 0m6.189s
sys 0m1.124s

どの言語もJavaに近い数字に。とりあえずポート接続の方が遅いですが1割程度のダウンだとコスト的には気にならないかと。

Java修正

ループの中で毎回PreparedStatementはご法度らしい。ループ外に出して再度計測。

ループ内で毎回セットしていたのをループ外に出してsetStringとexecuteQueryだけをループ内で回す。

Java(改善前) Java(改善後)
real 0m17.294s
user 0m6.189s
sys 0m1.124s
real 0m14.723s
user 0m3.705s
sys 0m0.827s

PHPやPerlに近づいてきた。ただしexecuteQuery()が遅さの9割以上を占めるのでこれ以上は改善の余地はなさそう。憶測だけれどたぶんJDBCが遅い。

ついでに他の速度改善を試みる

プレースホルダが重そうなんで取っ払う。社内システムなら必要性なし。可読性は落ちるけれど。

Go(socket) PHP(socket) PHP(port) Perl(port) Java
 real    0m11.660s
user    0m0.723s
sys    0m0.927s
real    0m7.810s
user    0m0.438s
sys    0m0.431s
real 0m9.237s
user 0m0.451s
sys 0m0.764s
real 0m12.149s
user 0m2.170s
sys 0m1.008s
real 0m14.376s
user 0m3.516s
sys 0m0.839s

PHPが大きく改善。2割以上の速度アップでPerlより速くなった。文字列処理の得手不得手かも。他に組み込み関数の強さを発揮しています。

まとめ

というか全体的な考察。Goが予想に反してそれほど速くない。後日SELECT周りをいじってみます。

意外と速かったのがPHP。ソケット接続でプレースホルダを使わないとJavaの2倍ほど速度が出ている。これは全くの予想外で、大量のデータを扱うときに有用でしょう。

Javaは重くなりそうな処理を常に意識しなければならないので、しっかりとプロジェクトを組める案件じゃないと難しい。

Perlはまあ適当に書いて適当に動かす用途に丁度いい。下手に書いても速度が変わらないのはありがたい。

 

Go

PHP

Java(遅いコード)

Java(PreparedStatementをforの外へ)

 

 

CodeIgniterで開発してみました(Uploadifyとの組み合わせ例)

久しぶりに新規開発案件があったので、せっかくなので新しいフレームワークを試して見ようと思い、前々から気になっていたCodeIgniterで開発してみました。
とは言え内製以外のPHPフレームワークでまともに開発に使用したのはEthnaくらいなので他との比較は出来ませんが、それでもこれは軽量の開発では特に使いやすい。特に海外で人気が高かったのも良くわかるフレームワークでした。

で、基本的な構造を把握すればあとは内製モジュールを適宜利用して大抵のことはちゃちゃっと出来たのですが、追加用件で複数ファイルのアップロードをしたいと要望が上がってきました。
ただ、CIのファイルアップロードクラスを見てもどうもそのままでは実現できそうにありません。

そこで外部プログラムと連携して実装することにしました。
さて、今回は
複数ファイルの一括アップロードに

  • Uploadify
    v3.2.1
  • jquery
    v1.11.0

を使用しました(開発時の最新バージョン)
Uploadifyとjqueryのファイルは解凍し、適当な場所に保存しておきます。

プログラム自体は複数の(.rar/.zip)ファイルを一括でアップロードしサーバ側で展開しつつ加工する、と言うものです。

  • 送信側テンプレート

  •  受け側関数(controllers/hoge.php)

この$upload_dataにはファイルアップロードクラスのお陰でファイルをいじるのに必要な情報がばっちり詰まっています。

http://codeigniter.jp/user_guide_ja/libraries/file_uploading.html
ですのであとはファイルを好きなように加工すればプログラムは完成です。

が、ここで問題が二点発生。

問題点1

CSRF防止設定との共存が出来ない。

CodeIgniterのconfig設定で

とするとアップロードに失敗してしまいます。

これを有効にすると常にPOSTの際にCookieとhiddenパラメータとを比較してCross Site Request Forgeryのチェックが行われるのですが、この場合、uploadify.swfがPOSTするためにCookieの値が無い状態となりチェックではじかれてしまうのです(flash版では無くHTML5バージョンだとどうなるかは不明)

試しに

と、CSRFトークンを明示的にPOSTするようにしても駄目でした。
コントローラ毎に

を切り替えられれば良いのですが、CI_Configクラスを拡張するなどが必要そうです。

と言う事で仕方なく

で運用し、適宜プログラム側でチェックすることで回避することにしました。

問題点2

アップロードエラーが発生しても通知できない。

通常のアップロード後にプログラムで処理しようとしてエラーが発生した際に、アップロード画面にエラーを通知出来ません。
uploadifyに付属するサンプルプログラムでは受け側で

とエラーメッセージを吐いている風ですが、実際にはifの結果がどちらでも処理はOKとなります。

解決策
POSTした祭のステータスでのエラーはハンドリングされているようなので
例によって受け側関数(controllers/hoge.php)にて

とすればUploadifyのflashのアップロード進捗画面にErrorが表示されます。

また、CodeIgniterの機能を利用してもっと簡単にここで

を実行すればデフォルトのstatus codeとして500が帰りますのでこちらを使いましょう。

と言うわけで

外部プログラムとの組み合わせのために若干の右往左往はあったものの、再度言いますがこれは学習コストも少なく人気のあるフレームワークなのも良くわかると言うものでした。

また簡単な開発案件があったら第一候補として使えそうです。

(が、どうもライセンス周りで色々と大変な様ですね……)

黄ばんだキーボード(プラスチック)を白くする

10年モノのRealForceが黄色くなり見た目が悪いので買い換えようとしたが、実験的なオモシロ作業を思い出したので試してみた。

IMG_2529

元ネタ – Retr0bright

過酸化水素と紫外線(日光またはブラックライト)で黄ばみを取ります。

過酸化水素を入手するのが面倒なのでワイドハイターexで代用。コンビニで売ってる。

IMG_2534

 

1本200円くらい。2本買ってきて漬けます(水を同容量ほど足しています)。

IMG_2538

キッチンペーパーで覆っても可。

さすがに冬場は日光に当てるのが住宅街だと難しい。ただ紫外線は日陰でも50%程度はあるらしいので、漬け置き時間でカバーします。

で、3日間漬けた結果がこんな感じ。

IMG_2540

 

だいぶ白くなった。まだまだ使える。

Dockerをドッカドッカと構築する

nigaraです。タイトル寒い。

CentOS6でDockerの構築。

Dockerインストール

  • epelレポジトリの追加。CentOS7は必要なし。

  •  dockerインストール。

Screenshot_from_2015-01-20 11:47:47

yum searchするとdockerとdocker-ioが表示されますが、dockerは同名の別物ですのでdocker-ioをインストールしてください(CentOS7だとdockerですが)。

  • docker起動

Screenshot_from_2015-01-20 11:48:40

以上でdocker本体の準備は終了。なんとも楽。

 

Docker操作

  • OSイメージの取得

Screenshot_from_2015-01-20 11:49:39

とりあえずubuntuを取得。他にFedoraやSlackwareなどもありますので、「docker search」やDocker Hub Registryで探せます。

  • OSイメージの確認

Screenshot_from_2015-01-20 11:50:12

取得したイメージが表示されます。

  • 起動&ログイン

Screenshot_from_2015-01-20 11:50:37

実はpullしないでrunしても自動でイメージを取得してくれます。

  • ログアウト&終了

ログアウトと同時にubuntuも終了します。

  • 再起動&再ログイン

まず コンテナ一覧を表示させる。

起動は「docker start (CONTAINER ID)」。

ログインは「docker attach (CONTAINER ID)」

  •  終了させずにログアウト(dettach)

Ctrl-pの次にCtrl-qでdettach。もしくはrunするときに

-dオプションを付ける。

  • コンテナ削除

コンテナを調べる

起動していたらストップ

削除

 

とりあえずdockerの基本的な使い方まで。