GAE開発の落とし穴
Googleのクラウド環境をつかったGoogle App Engineによる開発するにあたり、初めての試みで苦悩する開発者達の経験をもとに、各開発フェーズにあわせて問題点やどう解決したかをご紹介します
ブックマークされました!
ブックマークがエラーになりました。もう一度お願いします。
作者 Alex Blewitt , 翻訳者 徳武 聡 投稿日 2011年12月5日
Yammerの従業員であるCoda Hale氏がScalaの商用ベンダであるTypesafe社へ送ったメールがYCombinatorとGitHubのgist経由でリークした。メールによれば、Yammerは複雑さや性能面を鑑みて、基盤のインフラをScalaからJavaへ戻すそうだ。
YammerのPR部門のShelley Risk氏によればこのメールはCoda Hale氏の個人的な意見であり、Yammerの公式な見解ではないとのことだ。このリーク後、Coda Hale氏は自身の考えをhttp://codahale.com/the-rest-of-the-story/で表明している。氏はこのメールはDonald Fischer氏(Typesafe社のCEO)からのフィードバックの要請に答えたもので、移行を示唆するツイートを補足したものだと説明している。このメールを公にするつもりはなかったが、氏はこれをGitHubのGist(削除されているが)にアップし、友人からフィードバックを求めた。結果的にこのメールは広く共有された。
2010年8月、氏はYammerのエンジニアリングブログに、リアルタイム機能のためにScalaへ移行していると書いた。目標はJVM上(性能のため)でサービスを提供しつつ、約50%コードを削減することだ。
最初のArtieのプロトタイプはJavaで実装しました。しかし、週末になって試しにScala 2.8で再実装したところ、コードが半分になり、いくつか面白い機能も実装できました。私は納得しました。Javaを雇うのは簡単ですが、Scalaチームの方がいろいろなことができそうです。
しかし、1年と4ヶ月経つと、この決定は反転していた。
今、Yammerでは、基盤インフラをJavaへ移行しています。 Scalaはファザードとレガシなライブラリの部分で使い続けるつもりです。 急いではいません。始めたばかりです。この決定までには時間がかかりました。 Javaの代わりにScalaを使うことで生まれる軋轢や複雑さは、 Scalaの生産性や運用負荷の削減によっては埋め合わせできません。 まだ、Scalaを使っていますし、ずっと使い続けると思いますが、主要な開発はJavaで行うつもりです。
Stephen Colebourne氏は最近Scalaは新しいEJB2かという記事を書いたが、氏はこのメールに箇条書きで注釈を付けている。
このような問題のいくつかは状況に依存する(例えば、経験のある開発者の雇いやすくなればなるほど、ある言語は人気が出る)が、テストをすることもできる。例えば、アドバイスできることのひとつはforループを使わないことだ。これは下記のコードでテストできる。
scala>
var start = System.currentTimeMillis();
var total = 0;for(i <- 0 until 100000) { total += i };
var end = System.currentTimeMillis();
println(end-start);
println(total);
114
scala>
scala<
var start = System.currentTimeMillis();
var total = 0;var i=0;while(i < 100000) { i=i+1;total += i };
var end = System.currentTimeMillis();
println(end-start);
println(total);
8
上記の'until'を使ったforループ(多くのプログラマが普通だと思っている書き方)の処理は、whileを使ったループの処理に比べて読みやすいが、とても遅い。Javaの同様のループ処理の場合の結果は、forでもwhileでも同じ2ミリ秒だ。
mutableのマップにIntegerオブジェクトのデータセットをロードするを使った別のテストも行った(今回はJavaとScalaを比較した。ボキシングのコストは同等と想定する)。
scala>
val m = new scala.collection.mutable.HashMap[Int,Int];
var i = 0;
var start = System.currentTimeMillis();
while(i<100000) { i=i+1;m.put(i,i);};
var end = System.currentTimeMillis();
println(end-start);
println(m.size)
101
scala>
val m = new java.util.HashMap[Int,Int];
var i = 0;
var start = System.currentTimeMillis();
while(i<100000) { i=i+1;m.put(i,i);};
var end = System.currentTimeMillis();
println(end-start);
println(m.size)
28
scala>
val m = new java.util.concurrent.ConcurrentHashMap[Int,Int];
var i = 0;
var start = System.currentTimeMillis();
while(i<100000) { i=i+1;m.put(i,i);};
var end = System.currentTimeMillis();
println(end-start);
println(m.size)
55
普通のJavaのコードと比べるとjava.util.HashMapの場合は性能は同じだ。java.util.concurrent.ConcurrentHashMapを使った場合はJavaの方が同じScalaのコードと比べて2倍速い。両方ともScalaのHashMapよりも性能が良い。(計測環境はOSXとJVM 1.6.0_29、Scala 2.9.1。Scalaはこの記事を書いたときの最新のバージョン。)
残念ながらScalaのコレクションはScalaのライブラリAPIで広く使われている。従って、上記のコード上ではJavaオブジェクト型からScalaオブジェクト型に暗黙に変換される。くだんのメールによれば、これが性能問題を引き起こし、大幅な書き換えの原因になった。
Scalaのコンパイラがinvokedynamicを使ったコードを生成すれば、クロージャ(ラムダ)の性能は改善するかもしれない。これはScalaの将来のバージョンのコンパイラで実現するかもしれない。加えて、JDK 8(ネイティブのラムダとメソッドハンドルを提供する予定)には多くの性能上の長所があるので、将来のScalaもこれらの利点の恩恵を受けることができるだろう。
そして、Scalaに対して各リリース(2.9.2から2.9.3へのマイナーバージョンアップで互換性を維持するだけでなく)の後方互換性を維持するように求める圧力が高まっている。ScalaのロードマップについてはTypesafe社から正式な発表はない。また、いつコンパイルされたバイナリが各リリース間で後方(あるいは前方)互換性があるようになるのかも分からない。後方互換性があるようになれば、より安定したライブラリをリリースし、Scalaに興味がある開発者が誰でも利用できるコミュニティ用のリポジトリを準備することも出来る。
はじめまして。水島と申します。元記事の「ベンチマーク」については、これがベンチマーク
のやり方として良くないことが、英語版の記事のコメントにおいて、多数指摘されています。
たとえば、Alex Blewitt氏の示したベンチマークでは、ベンチマークに向いていない
対話型環境(通常のScala実行環境よりも実行が遅くなることがあります)を使って、
「1回だけ」、しかもms単位での計測を行っていますが、これはマイクロベンチマークの
一般原則を完全に無視しています。英語版の記事へのコメントを見ていただければわかり
ますが、実際の所、コードがJITコンパイルされる(これは、特にその部分が繰り返し実行
される場合に一般的な状況です)場合、forはwhileと同程度の性能になりますし、scala.collection.mutable.HashMap と java.util.HashMap の性能差についても、悪くて
2倍程度、良ければ同程度になります。
forとwhileの性能差の詳細な測定については、
d.hatena.ne.jp/chimerast/20110310/1299723622
のブログ記事も参考になると思います。
これは、この記事に限らず、英語版のInfoQ記事を翻訳される方にお願いしたいのですが、
元記事に対して反論が多数寄せられている場合、その全てを翻訳するのはさすがに無理だ
と思いますが、主要な反論を取り出して、両論併記の形にしていただけないでしょうか。
英語版の記事を読まない読者は、日本語版での偏った情報のみを目にする事になりますから、
結果として、記事の公平性を判断するための材料が無くなります。これは問題だと思います。
水島と申します。先ほどの、翻訳記事に関する私のコメントが少し一方過ぎたというご指摘を複数の方からいただき、考え直すところがありましたので、改めて投稿させていただきます。
まず、テクニカルな話については、概ね変わりありません。元記事(および翻訳記事
においても)ベンチマークは、ベンチマークとしては上手く機能しておらず、実際のScalaの
性能とはかなり異なります。また、元記事が参照しているCoda Hale氏の見解ですが、Scala
のバージョン間のバイナリ非互換性の問題など、的を射た指摘がいくつもあるものの、性能
特性については疑問が残ります。実のところ、Code Hale氏のパフォーマンスに関する
アドバイスは、Scala 2.7(~2010前半)では正しかったのですが、現在の安定版である
Scala 2.9では、forループに関する性能はかなり改善されており、JITコンパイルされた後
ではwhileループとほぼ同等の性能になります。また、コレクションについても、概ね
同様です。
次に、私が現在、InfoQ Japanの翻訳記事について問題意識を持っている事を挙げさせていただき
ます。今回のように、元記事が技術的な誤りを持っているまたはcontraversialなもので、元記事で多数の反論コメントが寄せられている場合、Twitterなどの一部メディアでは、
読者は、日本語訳された記事のみを読み、元記事への反論コメントは読まれない傾向がしばしば
あります。これは、以前の翻訳記事「Scalaは新しいEJB 2か」において、私が観察した限りで
実際に見られた傾向です。
ただ、実際の所、翻訳される方には、英語のコメント全てに目を通して精査している時間も無い
かと思います。そこで、提案させていただきたいのですが、原文へのリンクと共に、原文に対するコメント欄へのリンクをコメント数と共に表示していただく事はできないでしょうか。原文に対して、コメントがある程度ついている事がわかれば、原文がcontraversialなものである事がより読者にわかりやすくなるのではないかと考えます。
以上、先ほどは一方的な投稿、失礼いたしました。
水島様
InfoQJapanチーフエディタの羽生田栄一です。
本翻訳記事に対して重要なご指摘と追加情報をいただきまして、ありがとうございます。水島さんもおっしゃられる通り、InfoQ記事は興味深い技術情報に関しての速報性を優先しております。そのため、今回のような状況が時折発生しますが、ぜひ本コメント欄などを有効活用して、翻訳記事においても深い情報交換ができる場を作っていきたいと思います。翻訳者や日本側エディタも気が付いた範囲で、翻訳本文への追記修正や本コメント欄を利用しての記事投稿後の追加情報などを載せていければと思います。
なお、水島さんからのご提案についてはすぐに実現できるかは未定ですが検討させていただきます。今回は投稿ありがとうございました。
先ほどの投稿で、
> コードがJITコンパイルされる(これは、特にその部分が繰り返し実行
される場合に一般的な状況です)場合、forはwhileと同程度の性能になりますし
と書きましたが、これは少し勇み足でした。まず、Scala 2.8.2.final
(これはScala 2.8.X系列の最新メンテナンスリリースです)では、実際にforは
whileと同程度の性能でした。
d.hatena.ne.jp/chimerast/20110310/1299723622
のベンチマークコードを元に追試したところ、
|*micro sec|*.foreach|*.for|*.while|
|single|429|408|392|
|double|454|450|398|
|triple|736|758|472|
という結果になりました。ここで、triple(3重ループ)の場合、2倍近く遅くなって
いますが、これはinner loopにおけるオブジェクト確保が効いている可能性があります。
ともあれ、二重ループでも大差無い性能が出ているため、2.8.2に関しては問題ありません。
一方、Scala 2.9.1.finalで同じコードで測定したところ、
|*micro sec|*.foreach|*.for|*.while|
|single|1,084|1,104|401|
|double|5,637|1,152|388|
|triple|1,910|1,880|448|
という結果になりました。Scala 2.9.1.finalでは、通常のユースケースで、
forはwhileに比べて2~3倍程度遅いことになります。
元記事のベンチマークのやり方が適切でなく、実際の性能を反映していないという
結論には変わりありませんし、実用上forがこのくらい遅い事が問題になるケースは
多く無いでしょう。ただ、
> forはwhileと同程度の性能
は、Scala 2.9.1.finalにおいては正確ではなく、「forはwhileに比べて2~3倍程度
遅い」が正確ですので、訂正させていただきます。
Scala 2.9.1.finalでforの性能が遅くなっている理由は調査の必要がありますが、
Scala 2.9.0で並列コレクションが入ったので、そのための実装変更が原因になって
いる可能性はあります(これは推測ですが)。
なお、計測環境は、
CPU: Core i5-2430M 2.40GHz
OS: Windows 7 64bit (Home Premium)
Java実行環境: JRE1.6.0_29(server, 64 bit VM)
RAM: 8GB
となります。
Googleのクラウド環境をつかったGoogle App Engineによる開発するにあたり、初めての試みで苦悩する開発者達の経験をもとに、各開発フェーズにあわせて問題点やどう解決したかをご紹介します
去る1月12日、定理証明支援系ツールCoqの初心者向けチュートリアルが開催さ れた(http://kokucheese.com/event/index/23667/)。今後も2月2日 (http://kokucheese.com/event/index/23744/)、2月9日、2月16日と引き続き開 催されていく予定である。本記事では、開催の様子をレポートする。
Neal Gafter氏はOracleによるJava買収の影響に関する議論、Javaにセグメンテッドスタックやメタオブジェクトプロトコルを追加することについての主張、そしてJavaとC#との比較について話をしてくれた。
GoogleはVMをともなう新しい言語であり、JSコンパイラでもあるDartをプレビューした。 InfoQはDartのアプリの構築に貢献する文法の裏側を探った:スナップショット、Isolate、モジュール方式
本記事ではCSPベースの「マルチドメイン・モデル検査ツール」である、PAT(Process Analysis Toolkit)について紹介する。モデル検査は、形式手法(Formal Method)という方法論を基礎とする技術であり、複雑さが増大しながらも安全性を求められる、現在のソフトウェア開発の状況に対する処方箋の1つとして注目されている手法である。
前回まで、Jenkinsの幾つかの側面に注目して解説をしてきました。シリーズ最後の今回は、Jenkinsをサービスとして使う方法を紹介します。
Alloyは、MITにて開発された仕様記述言語であり、ツールによる自動解析を使い、インクリメンタルに形式仕様が書けることが特長である。筆者らはAlloy開発者による、Alloyを使った形式手法入門書を翻訳、今夏にオーム社より刊行した。本記事では、Alloyの簡単な概要と、翻訳書『抽象によるソフトウェア設計』(「Alloy本」)を紹介する。
スマートフォンを中心としたマルチデバイスにおけるタッチユーザーインターフェイスへの対応は、既に必須の項目となりつつある。本記事では、Windows デバイスにおける UX のベースとなっている「メトロ」というデザイン言語を掘り下げながら、既存環境を意識しつつもどのようにタッチユーザーインターフェイス開発に取り組んでいくべきであるかについて解説していく。
5 comments
スレッド表示 返信