読者です 読者をやめる 読者になる 読者になる

GDD2010でTim Brayに教わったこと

先日9月28日に開催された Google Developer Day 2010 に参加してきました。

中でも個人的におもしろかったTim Brayのセッションを紹介します。
「[AN-1] 高性能な Android アプリを作るには」というタイトルですが、内容はAndroidに限らない、ユーザーインタラクションを含むプログラミングに共通する基本的な考え方だと思います。


追記:動画が公開されたので貼っておきます。

UIスレッドを止めるな!

ユーザーエクスペリエンスの中で、パフォーマンスは重要な要素だ。
Androidマーケットでも遅いアプリの評価は低い。


では、何がユーザーにストレスを与えるのか?それはUIの応答速度だ。
一般に、ユーザーは100〜200ms以上反応がないと「遅い」と感じる。
そして、AndroidではFlashメモリやSQLiteへの書き込み*1、HTTP通信などに100ms以上かかってしまう。


すなわち、UIスレッドでIO処理を行ってはいけない。
IO処理を行う場合、非同期処理(AndroidならAsyncTask)を使うべきだ。


ユーザーの満足度を損なわないためには、非同期処理が完了する前に適切なレスポンスを返さなければならない。
例えば、ユーザーがクリックしたボタンを即座にdisableし、タイトルでスピナーを回す。もし処理が200ms以上かかるならプログレスダイアログを出す。といった感じに。

Don't guess! Measure!

"premature optimization is the root of all evil." (早すぎる最適化は諸悪の根源)


最初の実装から、明らかな速度低下要因の対策(例えば前述のUIスレッドからのIO処理分離)以上にパフォーマンス最適化を行ってはいけない。複雑なプログラムに対して、プログラマーが事前にパフォーマンスチューニングを行うことは不可能であると知るべきだ。


その実装で十分なパフォーマンスが出れば、OK。それでいいじゃないか。
もし十分でなかった場合、原因を推測しては行けない。測定せよ。
測定結果からボトルネックを割り出し、そこを修正する。
そしてまたパフォーマンスを測る。その繰り返し。


ここでクイズをしよう。
私のAndroidアプリ『LifeSaver』(SDカードのアドレス帳をコピーするアプリ)のボトルネックはどこだろう?

  1. SDカードからの読み込み
  2. SDカードへの書き出し
  3. その他のCPU計算部分


これはAndroidのプロファイリングツールで計測し、traceviewで見れば分かる(デモ)。
ほら、みんなの思った通りSDカードへの書き出しに時間がかかっているだろう?
しかしもっと注意深く見ると、実は書き出し処理の中のJSONフォーマットへの変換が大部分が占めていることが分かる。
つまり、さっきの答えは3番だ。


この計測によって、もし改善の必要があればJSONライブラリを変更するなり、フォーマットをJSONからバイナリに変更するなり、適切な対応がとれる。
もし推測に基づいて闇雲に書き出し処理を高速化していたら、パフォーマンスは全く改善されなかっただろう。


最後に一言。
Respct users, respect UI threads and respect measure!

Q&A

Q. C2DM (Cloud to Device Messaging) はスケールするのか?例えば100万ユーザーとかで使っても大丈夫なのか?

A. We are Google.

                                              • -

以上です。
重たい処理をUIスレッドから分離するのは、JavaScriptでも常套手段ですね。
プログラマーの性として、ついつい実装中に最適化をしたくなる誘惑にかられるわけですが、このあたりは肝に命じていきたいと思います。
それにしても、質疑応答にはしびれました。。

*1:ただしFlash writeの速度は数msから200ms超までかなり変動するらしい。