SunSpider JavaScript Benchmarkを移植してJSXとJavascriptの速度を比べてみた
JSXの特徴は、トップページにも書いてあるとおり「faster, safer, easier」の3つです。安全性とか簡単さについては人とか状況によって様々な定義や意見がありますが、唯一Fasterだけは客観的に測れます。
しかしJSXと速度については、トップページにあるBox2Dとshootingのデータ*1とAOBench on JSXぐらいしかありません。
というわけでWebkitで使われているSunSpider 1.0.2 JavaScript BenchmarkをJSXに移植してJavascriptと速度を比較してみました。*2
環境
改善率まとめ
正の場合はJSXのほうが速く、負の場合はJSXのほうが遅い。
最善 | 最悪 | 平均 | |
---|---|---|---|
iPhone | 67% | -97% | -12% |
iPad | 73% | -91% | -7% |
Safari | 47% | -90% | -14% |
Firefox | 89% | -73% | 18% |
Chrome | 35% | -88% | -3% |
結論
- regexp-dnaがすごく遅い。JSXに複数行文字列リテラルがなく、実行時にArray#joinで生成しているため。
- regexp-dnaを除けば、JavascriptとJSXは大きな速度差はない。「絶対に遅くならない」は達成できているのではないか。
JSXよりHaxeがイケてる5つの理由(実践編) もしくは Real World Haxe
JSXがリリースされて1週間ぐらい立ちました。ガシガシ進化が進んでてすごいですねー。
おかげで、文法と適用範囲が似てるHaxeにも注目を集まっている気がします。なので、今日はそのHaxeを実際のプロジェクトに適用した事例について紹介したいと思います。題してReal World Haxeです。
プロジェクト概要
プロジェクトの概要は、前にosiireさんが2009-10-21で書いているのでそのまま引用します。
某自動車販売会社用のWebサービス
サーバーサイドを全部OCamlで作成。OCaml+MySQL。既に稼働中のサーバーへ導入しなければならず、その環境が少し古かった(debian serge)ので一瞬焦ったが、ちゃんとOCaml開発環境は揃った。初めてpa_monadを導入したが、とても便利だった。重回帰分析をOCamlで実装した(Cで書くのがイヤだったから)。OCamlのコードはトータル4000行程。
上記の記事ではサーバサイドにしか触れられてませんが、クライアントサイドには過去の販売状況をグラフ表示するためにFlashが用いられていました。 そのFlashを開発するにあたりHaxeが採用されました。
コードサイズはトータルで8000行程度で、開発体制は4名ほどでした。まあ一人はアルバイト(ボク)でしたが。
イケてる理由1) 型推論が強力
JSXにも型推論が実装されていますが、関数呼び出しの引数に無名関数リテラルを渡したときに型注釈を省略できる、といった程度の限定的なものです。今後、型推論できる箇所は増えていくと思いますが、後付けで型推論を追加しているため限定的なものに留まらざるをえないと思います。
一方、Haxeは最初から型推論を意図して設計されているため、ほぼ全ての箇所で型を省略できます。
// サーバからT型のデータを取得するクラス class Request<T> { function new(url : String, onLoad : T -> void) { // ... } } // サーバサイドからMarket情報を取得するクラス class MarketRequest extends Request<Market> { // superに渡すため引数の型が推論可能 function new(url, onLoad) { super(url, onLoad); var http = new Http; // onErrorの型から無名関数の型を推論可能 http.onError = function(error){ }; } }
ただ、あまりに省略すると読みづらくなってしまうので、
- 型が分かりにくい引数には型注釈をつける
- ある程度複雑なクラスは型注釈をつける
などの対応をしていました。
イケてる理由2) 関数レベルの多相性
JSXもテンプレートをサポートするようになりましたが、現時点ではクラスのみが型パラメータを受け取ることができ、関数は受け取ることができません。そのため配列をmapして別の型の配列を作り出すことはできません。
// JSXだよ! // 内部データをグラフ上の点に写像したい var data : Array.<MyData> = … // mapの返り値はArray.<MyData>固定 var pts : Array.<Point> = data.map<Point>(function(x : MyData) : Point { return conv_my_data_to_point(x); })
一方、Haxeでは関数ごとに型パラメータを持たせれるため、別の型の配列を作り出すことができます。
// Haxeだよ // 元データから日付と値のペアを作る var xs : List<Pair<Int, Int>> = Lambda.map(data, function (x) { return new Pair(x.getDate(), x.getValue()); })
イケてる理由3) Option型とEither型
enumのすばらしさに書くつもりだったんですが、実際にgrepしてみたらほとんど使われていませんでした。せいぜい、グラフの描画オプション程度でした。
しかしenumのおかげでOption型とEither型を定義することができ、nullを使うのを避けれました。
// 失敗するかもしれない計算を表わす enum Option<T>{ None; Some( v : T); } // 失敗した場合のメッセージも付与する enum Either<A, B>{ Left( v : A ); Right( v : B ); }
イケてる理由4) 構造的部分型による柔軟なクラス定義
通常の名前によるインタフェースはまったく使わずに、すべて箇所で構造的部分を使いました。たとえば、X軸を描画するためのクラスの型は次のように定義されています。
typedef XAxis = { function draw(state : TState) : Void; }
そして、各グラフクラスは、このXAxis型を使って描画処理を実装します。
class SimpleGraph { public var xaxis : XAxis public function draw(state : TState){ xaxis.draw(state); …. } }
当然SimpleGraphクラスを使う場合はxaxisフィールドへの代入が必要です。ただし、構造的部分型のおかげで、クラスを宣言する必要なくその場でオブジェクトを作ることができます。
var graph = new SimpleGraph graph.xaxis = { draw : function(state) { ... } };
本来は、あとからXAxisWithSomeGreatFeatureみたいなのを定義できる拡張性を残すための設計だったのですが、実際はほとんど拡張が必要になることはありませんでした。構造的部分型を使ったことで記述量も増えたわけでもないですし、可読性・安全性も損なわれていないのでいいんじゃないですかね。
イケてる理由5) 開発環境、ドキュメントが揃っている
開発環境も充実しており、Windows+FlashDevelopでも、Windows + VirtualBox + Linux + emacsでも問題なく開発できました。(後者はボクです)
また公式ドキュメントも、関数型プログラミングのバックグラウンドを持っていない人でも問題なく書ける程度にはそろっていました。
残念だったところ
当然いいところだけでなく、残念だったところもいくつかありました。
まとめ
Haxeは実プロジェクトへの適用事例もあるし、みんな使うといいと思うよ。
JSXよりHaxeがイケてる3つの理由
Javascriptを生成できる言語『JSX』がリリースされました。めでたいですねー。
ただ同じくJavascriptを生成きるHaXeのことが忘れられている気がするので、宣伝します。 ステマじゃないよ!
型推論がイケてる
現時点でJSXには型推論が実装されてないので、関数を定義するには全ての型を書く必要があります。
// JSXだよ! function add(x : number, y : number) : number { return x + y; }
これだけなら特に問題ないように見えますが、これが高階関数を定義しようとするとどんどん複雑になっていきます。
// JSXだよ! function f(g: function(:number):number): function(:number):number { return function(x: number): number { return g(x+1); }; }
一方、Haxeには型推論が実装されているので、上記のコードから大部分の型注釈を省略できます。
// Haxeだよ! function add(x,y) { return x + y; } function f(g : Int -> Int) { return function(x) { return g(x+1); } }
文法がほどんど変わらないにもかかわらず、型推論ができるのでイケてます。
型が柔軟
Haxeの型システムはとても柔軟なので、静的型付けの安全性を損なうことなく、様々なコードを書くことができます。
ジェネリクスはそのうちJSXに入るでしょうし、enumのすばらしさについてはbleisさんがすでに書いているので、ここでは省略して構造的部分型について解説します。
まず、こんな感じのPersonクラスがあったとします。名前と性別を持っています。
// Haxeだよ! class Person { public var name : String; public var gender : String; public function new(name : String, gender : String){ this.name = name; this.gender = gender; } }
また、こんな感じのBookクラスもあります。名前だけを持っています。
// Haxeだよ! class Book { public var name : String; public function new(name : String){ this.name = name; } }
このPersonクラスとBookクラスは共通のnameフィールドを持っていますが、継承関係がないのでnameフィールドを取り出す関数を書けないような気がします。
function getName(x : ????) { return x.name; }
しかしHaXeでは、「nameというフィールドを持ったオブジェクト」を表わす型を扱うことができます。これは構造的部分型と呼ばれます。これを使うと、下記のようなコードを実現できます。
// Haxeだよ! // String型のnameフィールドを持つオブジェクトを受け取り、そのnameフィールドを取り出す関数 function getName(x : { name : String}) { return x.name; }
同程度の速度で動く
JSXの速さのキモはインライン展開らしいです。
一方、Haxeにはinlineキーワードがあるので任意の関数をinline展開するよう指定できます。 インライン展開できない関数に対して指定した場合は、コンパイル時にエラーになります。
// HaXeだよ! inline static function getName(x : { name : String } ) { return x.name; }
inlineキーワードを適切に指定することで、AOBenchをJSXと同等程度の速度で動作させることができるそうです。
まとめ
- Haxeはイケてる言語だよ
- こんな機能がJSXにもはいるといいなぁ
おまけ
速度比較をするためにaobenchをHaxeに移植したのですが、一晩のうちにチューニングによりHaxeがJSXを抜き、その翌日にJSXコンパイラが修正されて再び抜かれる、という流れが一日でおこりました。JSXは進化が速くてすばらしいです。 → JSX v.s. HaXeベンチマーク戦争 - Togetter
Redmine, git, Jenkinsの状態を横断的かつリアルタイムに表示する『Dashbozu』をリリースしました。
Redmine, git, Jenkins などプロジェクト管理ツールの状態を横断的かつリアルタイムに表示するWebアプリ『Dashbozu』を作りました。
これを使えば、一つの画面でプロジェクトの”今”の状態を把握できます。 WebSocketを用いているので、ただ開いているだけで、次々と情報を得ることができます。
iPadで開きっぱなしにして、机の上に置いておくような使い方を想定しています。
なぜこれを作ったか
一般的なソフトウェア開発現場では
という流れで作業が進んでいきます。
これらの作業の中で、開発者は「適切な」タイミングでチェックとフィードバックをすることを求められます。
例えば、チェックのタイミングが遅すぎると、壊れたビルドが放置されたり、チケットが更新されたのにレビューされていないコードが溜ったりしてしまいます。一方、早過ぎるコードレビューは開発者がまさに修正中の内容と重複してしまうことがあり、効率的ではありません。
つまり、適切なタイミングとは、例えば以下のようなものです。
- Gitでpushしたタイミング ・・・ 開発者が仕様を勘違いしていないか
- Jenkins のビルドが完了したタイミング・・・ビルドが壊れていないか
- Redmineのチケットのステータスが変更になったタイミング ・・・ コードレビュー
これらのチェックを早すぎず遅すぎないタイミングで行うためには、リアルタイムで通知を受け取らなければなりません。しかし、メールや IRC への通知や XFD などで受け取る場合は、各アプリ毎に常にチェックしていなければいけないため、非常に面倒くさいです。
そこで、横断的かつリアルタイムなビューを提供するDashbozuを開発しました。
Dashbozuの主な機能
WebSocketを用いたリアルタイム通知
WebSocketを利用したPush通知を採用しているので、ページのリロードをすることなく最新の情報を得ることができます。
ダウンロード・インストール方法
長野で開発合宿をしてきました
id:suerさんが書いているように、4/28-4/30の連休に長野で合宿をしてきました。成果物はもうちょっとしたら公開するよ!
一日目
15時ごろにチェックインしたので、とりあえずレッドブルを積んでピラミッドを作りました。 最終日にはこのレッドブルを全て消費していたので、おそろしいものです。
ひとしきりレッドブルタワーの写真を撮ったあとは @suerさんがラフスケッチを元に、概要図を書いたり、シーケンス図を書いて、作るソフトのイメージを固めました。
Play frameworkをインストールしたり、静的なHTMLでモックを作ったりしたあたりで力尽きて寝落ちしました。
二日目
宿の付近を散歩していたら、スキー場についてしまい、おおいにビビりました。たぶん、あそこはサンダル+Tシャツの人間が行ってはいけない場所です。
その後、DBへデータを格納する部分などの各種部分ができあがって、とりあえず動くようになったので記念撮影をしました。 あれだけの人数が居て、その場に存在したガジェットがiPhone/iPad/MacbookAirのみというのは、なかなかに気持ちの悪い光景でした。
三日目
帰らないといけないのであまり時間がなかったのですが、iOSへのPush通知(Apple Push Notification)への対応をやりました。
最初はim.kayac.comを使うつもりだったのですが、複数のデバイスへの同時通知がやりにくいAPIだったので、結局boxcarを使いました。
途中、プログラムがバグって、ひたすら@suerさんのiPhoneが鳴り続けるということもありましたが、最終的にはうまく動くようになりました。
まとめ
たのしかったけど、これが三日以上になると、死ぬ気がします。
あとしばらくカフェインはひかえます。
SCM Boot Camp in Nagoyaに行って、Darcsの紹介してきました
@kyon_mmさんに誘わてSCM Boot Camp in Ngaoyaに行ってきました。 当日はGitのサポータしたり、ワッフル食べたりしてました。ワッフル、実においしかったです。
参加する2週間前ぐらいになんとなくDarcs/CAMPのことを調べてたらガチですごかったので、懇親会の闇LTでDarcsの紹介をしてきました。いや、マジですごいんですって。
LT資料『Darcsの紹介』
何がすごいか
いきなりボクの勝手な妄想でアレですが、gitとかmercurialとかの他の分散管理システムは単に実装があるだけか、あるいは、せいぜいレポジトリフォーマットの仕様がある程度だと思っています。
一方、Darcsは「変更とは何か」「マージは何をやるか」といったことを形式的に定義したPatch theoryを作り、その上で実装を行なっています。
そのおかげでこんなすばらいしことがあります。
- マージやパッチの並び換えの正しさは証明されているので、致命的な欠陥はありえない (実装ミスはあるかも..)
- Darcs特有の機能は(あまり)ないので、他のDVCSの挙動の理解にも役立つ
- 抽象的に定義されているので、他の言語や他の用途に流用しやすい
何が証明さているか
まだ参考文献を読み切れていないのですが、少なくてもPatch theoryでは以下の性質が証明されています
- どういう状況なら、cherry-pickしても問題がないか
- どういう状況なら、パッチを並び換えても結果がかわらないか
- どういう状況なら、マージ可能か
まとめ
Darcsすごいので、みんな勉強しましょう!
ブランチを持っていなかったりしてツールとしてはちょっと微妙な気もするけど、それでもなおDarcsはすばらしいのです。
開発者向けリアルタイムチャットアプリケーション『AsakusaSatellite』 0.7をリリースしました
前回のバージョンアップからだいぶ時間が空いてしまいましたが、AsakusaSatelliteの新バージョンのリリースを行ないました。
前回まではSkypeで相談しながら開発するというスタイルでした。しかし、今回のバージョンアップで機能が多数追加されたことによりAsakusaSatelliteで相談しながらAsakusaSatelliteを開発するというドッグフードスタイルによる開発が可能となりました。
AsakusaSatelliteの特徴
AsakusaSatelliteは以下のような機能をもった開発者向けチャットアプリケーションです。
今回のバージョンアップにより追加された機能
v0.7 のバージョンアップのキーワードは「AsakusaSatellite as a Service」であり、PaaS対応を意識しています。
その結果、従来よりもプラガブルな構成になっています。
PaaS(heroku)対応
今回のバージョンアップの最大の変化点は、herokuに対応したことです。 これにより自前でサーバを持たずにAsakusaSateliteを利用できるようになりました。
もちろん、今まで通りローカルのサーバで動作させることもできます。
これにともないDBがGroongaからMongoDBに変更されました。
WebSocketサーバの外部サービス対応
PaaS対応の一環で、WebSocketサーバを切り替えられるようになりました。
現在は以下の3つの WebSocket サーバを利用できます。
内部にリソースを持ちたくない場合には、Pusher を利用し、内部で閉じた形で利用したい場合には、Socky ベースの WebSocket サーバを利用する、といった使い分けが可能です。
また合せてChrome16への対応も行なっています。
部屋の非公開設定
部屋を特定メンバのみに公開することができるようになりました。この機能により、herokuのようなpublicなサーバに設置した場合でもプライベートな情報を守れます。
部屋ごとの設定となっているため、一般用の部屋を公開し、身内用の部屋を非公開にするといった併用も可能です。
QuoteIt対応
プラグイン機能によりQuoteItと連携できるようになりました。これによりAsakusaSatellite上でTwitter、Slideshare、Gistなどを簡単に引用することができます。
また、QuoteIt は世界中の開発者が自由にプラグインを追加できるので、利用しているうちに機能が追加されている、ということも起こりえます。
ただし、すべてのURLをQuoteItに送るため、セキュリティの観点からデフォルトでは無効になっています。
周辺ツールの充実
AsausaSatelliteを日常的に用いるようになったため、周辺ツールが整備されました。
AsakusaSatellite Plugin for JenkinsをJenkinsにインストールすることで、ビルド結果をAsakusaSatelliteに通知できるようになります。Redmineチケットリンクプラグインによって、コミットメッセージに埋めこまれたチケット番号が展開されるので、非常に分かりやすい通知になります。
ダウンロード・インストール方法
公開ページからパッケージを取得し、適当なディレクトリに展開します。
依存ライブラリをインストールします。
$ bundle install --path vendor/bundle
環境に応じてMongoDBの起動を行ないます。
$ mongod --dbpath <dir_name>
WebSocketサーバであるSockyを起動します。
$ bundle exec thin -R socky/config.ru -p3002 start
AsakusaSatellite本体を起動します。
$ bundle exec rails server
http://localhost:3000/ でAsakusaSatelliteが利用できます。
また詳細なマニュアルも公開しています。