【和訳】Android Architecture Components ViewModel

自分で理解するために ViewModel | Android Developers (原文) を訳しました。

サンプルコードや図を全て写していないので、原文を見ながら適宜理解を深めるのに利用してください。また、理解しやすいよう所々補足を加えています。先にアクティビティの実行時の変更処理について理解しておくと読みやすくなります。

 

ViewModel

ViewModelクラスはUIに関連するデータの保持と管理をするようデザインされています。そのため画面回転などの設定変更があってもデータは保持されます。

NOTE: ViewModelをAndroidプロジェクトにインポートするには、adding components to your project を見てください。

アクティビティやフラグメントなどのAppコンポーネントAndroidフレームワークによって管理されるライフサイクルを持ちます。
Androidフレームワークは、開発者がコントロールできないユーザーのアクションや端末のイベントに従って、ActivityやFragmentを破棄または再生成するか決めます。
Activity/FragmentのオブジェクトがOSによって破棄または再生成されると、それらが保持していた全てのデータは破棄されます。
例えば、ユーザーのリスト(List<User>)をActivityが持っていて、設定変更によってActivityが再生成されると、新しく生成されたActivityはリストデータを取得し直さなければなりません。
データが単純ならActivity#onSaveInstanceState()メソッドを使って、Activity#onCreate()でBundleからデータを修復することができます。
しかしこの方法は、UIの状態など少量のデータに向いています。サイズが大きくなりそうなユーザーのリスト(List<User>)には向いていません。

他にも問題があります。activityやfragmentなどのUIコントローラーは戻るまでに時間のかかる非同期の処理を頻繁に呼ぶ必要があります。
UIコントローラーはそれらの非同期処理を管理する必要があります。非同期処理が中断されたら、メモリリークを避けるためそれらを片付ける必要があります。
これは多くの管理を必要とします。また、オブジェクトが設定変更によって再生成されて、同じ処理が呼ばれることはリソースの無駄使いです。

最後にこれも重要なことですが、これらのUIコントローラーはユーザーのアクションに反応したり、OSとのコミュニケーションに対応する必要があります。
そして自身が持つリソースも管理することになると、クラスは膨れ上がります。
そのような状態は、1つのクラスがアプリのすべての機能を他のクラスに委譲せずに自分自身でやろうとすることになります。このような状態はテストを難しくします。

Viewに必要なデータのオーナーシップをUIコントローラーのロジックから分離するのが簡単で効果的です。
ライフサイクルパッケージはViewModelと呼ばれる新しいクラスを提供します。これはUIコントローラー(Activity/Fragment)のためのヘルパークラスで、UIに使うデータを準備する役割を担います。
ViewModelは設定変更があっても自動的に保持されます。そのため、ViewModelが持つデータは再生成されたActivity/Fragmentですぐに利用できます。

前述しましたが、ユーザーのリスト(List<User>)を取得し保持するのはActivityやFragmentではなく、ViewModelの責任であるべきです。
もしActivityが再生成されても、再生成された新しいActivityは、前のActivityによって作られたものと同じViewModelのインスタンスを受け取ります。
Activityが破棄されると、AndroidフレームワークはViewModel#onCleared()を呼び、ViewModelのインスタンスは破棄されます。

NOTE: Activity/Fragmentの初期化時にもViewModelは生き残ることから、ViewModelはViewを参照するべきではありません。
またどんなクラスでもそれがActivityコンテクストの参照を持つ場合は、そのクラスを参照すべきではありません。
もしViewModelがApplicationコンテクストを必要とする場合は、提供されているAndroidViewModelを継承して、コンストラクタでApplicationを受け取ってください。(ApplicationクラスはContextを継承しています)

 

Sharing Data Between Fragments

2つ以上のフラグメントが1つのアクティビティの中で、連携を取り合うことはよくあることです。
2つのフラグメントがインタフェースを定義し、オーナーであるactivityが2つを結ぶことは、珍しいことではありません。
さらに2つのフラグメントはお互いが存在するか、visibleな状態であるか考えなければなりません。
このよくある問題は、ViewModelオブジェクトを使って解決できます。
よくあるmaster-detail fragmentsのケースを想像してください。アイテムリストを表示するfragmentからユーザーがアイテムを1つ選ぶと、選んだアイテムの詳細を表示するfragmentが出てくるパターンです。
この2つのfragmentは、Activityのスコープを使って、お互いのコミュニケーションを管理するためにViewModelを共有することができます。

gistbd67d578044e830ee00943b0e43145e7

2つのfragmentがVIewModelProviderを利用する際、getActivity()を使っていることに注意してください。これは2つのFragmentが同じactivityの範囲で、SharedViewModelのインスタンスを受け取ることを意味します。

このアプローチの利点:

  • Activityは何もする必要がありません。fragmentsのコミュニケーションについて知る必要もありません。
  • FragmentはViewModel以外、お互いを一切知る必要がありません。片方が消えても、もう片方はいつも通り動き続けます。
  • 各Fragmentはそれぞれのライフサイクルを持ちます。もう片方のライフサイクルの影響を受けることもありません。実際、Fragmentが他のFragmentに入れ替わっている間も、UIは問題なく機能します。

ViewModelの機能は、ViewModelを取得する際ViewModelProviderに渡したライフサイクルの範囲で利用できます。(activityを渡したら、activityがfinish()されるまで利用できます。)
ViewModelは、ライフサイクルが終了するまでメモリに置かれます。activityならActivity#finish()、fragmentならFragment#detached()が呼ばれるまで、メモリに残ります。

 

ViewModel vs SavedInstanceState

ViewModelは、設定変更があってもデータを保ち続けるための簡単な方法を提供します。しかし、アプリケーションがOSによってkillされるときは破棄されます。
例えば、ユーザーがアプリを離れて、数時間後に戻ってきたとき、すでにプロセスは終了され、Android OSが保存されたデータからActivityを復元しています。
すべてのframeworkコンポーネント(views, activities, fragments)は、saved instance state機能を使って状態を保存します。
ほとんどの場合、開発者は何もする必要がありません。開発者はonSavedInstanceStateコールバックを使ってデータをbundleに追加するだけです。

onSavedInstanceStateを使って保存されたデータは、システムのプロセスメモリに保持されます。そして、Android OSは開発者にとても少ない量のデータを保持することを許可しています。
そのため、実際のデータ(アプリが使うコンテンツデータ等)を保持させるのに適した場所ではありません。
開発者は、UIコンポーネントによって簡単に置き換えられないデータのためにプロセスメモリを使うのは控えましょう。
例えば、Country情報を見せるユーザーインターフェースがあっても、絶対にCountryオブジェクトをsaved instance stateに入れないでください。countryIdを入れることはできます。(ViewやFragment argumentにすでに保存されていなければ) 実際に利用するオブジェクトはデータベースに入るべきです。そしてViewModelが保存されたcountryIdを使って、オブジェクトを取得します。

Manage environmental variables safely with Android Studio.

When you wanna share an Android app's source code on GitHub(or any sharing service), you shouldn't write any secret keys inside your app.
This is a way to hide these values from entire world. :)
 
1. Create or edit ~/.gradle/gradle.properties and define secret keys.
(Pay attention to the position, it's placed in USER HOME DIRECTORY!!!!!)

~/.gradle/gradle.properties

ProductionApiKey="production-api-key"
StagingApiKey="staging-api-key"


2. Read them in application level build.gradle.
In the example below, both of ProductionApiKey and StagingApiKey are named as "API_KEY".

app/build.gradle

flavorDimensions ( "api" )
productFlavors {
    prduction {
        dimension "api"
        buildConfigField "String", "API_KEY", ProductionApiKey
    }
    staging {
        dimension "api"
        buildConfigField "String", "API_KEY", StagingApiKey
    }
}


3. Use these values in your code.
Select productionDebug build variant and run it.
You'll see the log message "production-api-key". Yay!

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    System.out.println(BuildConfig.API_KEY); // -> production-api-key
}

ロゴの使用許可申請メールテンプレート

ロゴの使用許可申請メールを作成したので、テンプレートメモ。

カンファレンスの発表資料に他社のロゴを掲載したいとき用と他社サービスのAndroidクライアントをGoogle Play Storeに申請したいとき用。

Dear Permissions Editor,

An employee of our company is scheduled to give a presentation at AWS Summit in Tokyo on June 2, 2017.
I would like your permission to include your company's logo for non-commercial purposes in his presentation.
Also, we'd like to display a number of middleware logos as well, so that the audience understands that we're using your product with AWS.

I would greatly appreciate your consent to my request.
If you require any additional information, please do not hesitate to contact me. I can be reached at:

[メールアドレス]

Sincerely,

[名前]

 

Dear Permissions Editor,

I am in the process of developing a Redash application for Android.

I would like your permission to release this application to Google Play Store.

The project is including the following materials:

Your product’s name. (Redash)

Product’s logo. ( https://camo.githubusercontent.com/65ab82a5dbb122630e4d4d61383c48b6a1aff1f1/68747470733a2f2f7265646173682e696f2f6173736574732f696d616765732f6c6f676f2e706e67 )

Your Project’s license. ( https://raw.githubusercontent.com/getredash/redash/master/LICENSE )

The application will be used to display Redash dashboards which the user has registered to the app. Also, I would like to declare that your project is licensed under the BSD 2-clause “Simplified” License on the store product page, so the app user will understand that I’m a third party.

I would greatly appreciate your consent to my request.

If you require any additional information, please do not hesitate to contact me. I can be reached at:

[メールアドレス]

Sincerely,

[名前]

おわり。

 

10 steps to get started with Realm for Android.

This article is written for someone who just wants to give it a try anyway.
If you're interested in details, please read the official docs.
The application that you're going to make from now, inserts 1 user with 2 breads every time you start the app. :)

1. Add this line to the project level build.gradle.

classpath 'io.realm:realm-gradle-plugin:3.1.4'

2. Add this line to the top of the application level build.gradle.

apply plugin: 'realm-android'

3. Refresh gradle dependencies.

4. Configure a Realm in MyApplication.java.

5. Add MyApplication to application tag in the app's AndroidManifest.xml.

<application
      android:name=".MyApplication">
</application>

6. Create a User class.
You can mark a field as a primary key with @PrimaryKey.
Other annotation types summary is HERE.

7. Create a Bread class.

8. Write insert function in MainActivity.java.
As I mentioned before, this app inserts 1 user and 2 breads into Realm DB when onCreate() is called.
There is an auto-incrementing ID helper but it's not recommended when you:

1) Create Realm Objects in multiple processes. 2) Want to share the Realm between multiple devices at some point in the future.

Here is an example of auto-Increment ID for creating objects across processes.

Example of delete function.

User u = mRealm.where(User.class).equalTo("id", id).findFirst();
u.deleteFromRealm();

9. Copy database to somewhere accessible.
Realm provides a Mac app to edit and read your database.
Currently, this app doesn't support accessing database directly.
You have to copy it from emulator or device to somewhere accessible.

$ adb shell "run-as your.package.name chmod 666 /data/data/your.package.name/files/default.realm”

$ adb exec-out run-as your.package.name cat files/default.realm > default.realm

$ adb shell "run-as your.package.name chmod 600 /data/data/your.package.name/files/default.realm"

10. View your database in Realm Browser.
f:id:bambinya:20170509194932p:plain:w300
Choose 'Open Realm File' and you can view it.

User table
f:id:bambinya:20170509193706p:plain:w540

Bread table
f:id:bambinya:20170509193711p:plain:w540

You're done!
Now you're able to explore Realm world by yourself. Enjoy! :)

BitcoinのBlockとTransactionのデータ構造について

BitcoinP2P通信技術を利用している。Bitcoinネットワークに参加する各ノードはクライアントとしてもサーバーとしても動作し、データの生成と送受信を行う。各ノードが持つデータはほとんど同じである。(常にノード間でブロックとトランザクションをやり取りしているのでいつも全く同じデータではない)

 

新しいノードがBitcoinネットワークに参加する流れ

  1. Bitcoinのソフトウェアをインストールし、デーモンを起動する。
  2. Seedsから他のノードのIPアドレスを聞き出す。
  3. 他のノードに過去の取引データ(ブロックチェーン)を送ってもらう。送られたデータは主記憶装置に保存される。

https://github.com/bitcoin/bitcoin リポジトリは、CLI(コマンドラインインターフェース)を持っている。ソースをクローンし、デーモンを起動する。初めてネットワークに参加するノードは、他のノードのIPアドレスを知らない。そのため、Seedsというノードを利用する。Seedsと呼ばれるノードは常に稼働していることが期待されている。ネットワークに新しく参加したノードは、まずSeedsに他のノードのIPアドレスを聞く。Seedsのリストはbitcoin/src/chainparamsseeds.hに記載されている。

手に入れたIPアドレスを元に、他のノードに過去の取引データを送信してもらう。送られた取引履歴は主記憶装置に保存する。保存先は${HOME}/.bitcoin/以下である。取引履歴には、ブロックチェーン、トランザクションリスト、UTXOなどがある。2017年2月の時点で保存されるデータ量はMain Networkは100GB、Test Networkは40GB程度である。

 

ノード間でブロードキャストされるブロックとトランザクションのデータ構造

前述したように、各ノードが生成したトランザクションやブロックは他のノードにブロードキャストされ、常にデータの同期が行われている。では、トランザクションとブロックは実際どのようなデータ構造をしているのだろうか。

 

ブロックのデータ構造

ブロックは複数のトランザクションを含む。

先頭にネットワークを識別するマジックナンバーを持ち、ブロックのサイズ(1MByte以下でなければならない)、直前のブロックのhashなどを持つブロックヘッダー、内包するトランザクションの数と、最後にトランザクションデータを持つ。

f:id:bambinya:20170225222746p:plain

詳細はBitcoin Wikiに書かれている。

f:id:bambinya:20170304170353p:plain

 ( Block - Bitcoin Wiki )

 

ブロックヘッダーのデータ構造

ブロックヘッダーは6つの要素を持つ。

ブロックのバージョン、直前のブロックのヘッダーのHash(256bit)、ブロックが含むトランザクションのRoot Hash(256bit)、時間(秒)、ターゲット、Nonce(32bit)である。

f:id:bambinya:20170304195715p:plain

Block hashing algorithm - Bitcoin Wiki )

 

トランザクションのデータ構造

トランザクションは取引内容を表すデータを持つ。Bitcoinは実体がないため、どれだけの量のBitcoinがどのアドレスからどのアドレスに移動したか、という内容である。

支払い者がどのアドレスからいくらのBitcoinを受け取ったかをInputと呼ぶ。そして、どのアドレスにいくら支払うかをOutputと呼ぶ。

データ構造は下記のとおりである。先頭にバージョン番号、取引に使うInputsの数、Inputsのリスト、 取引に使うOutputsの数、Outputsのリスト、最後にlock timeを持つ。

lock timeには、取引がブロックに含まれる条件を指定することができる。詳細は

前回の記事で述べた。

f:id:bambinya:20170305100110p:plain

Transaction - Bitcoin Wiki )

BitcoinとBlockchainについて調べたこと

Bitcoin: 非中央集権型の電子通貨。非中央集権型とは、銀行などの信頼された金融機関が取引に関与しないことをさす。金融上の取引を行う際、銀行の役割は支払い者に支払いの能力があることと、取引が不正ではないことを保証することである。Bitocinは、そのような信頼される第三者を取引に必要としない。

Block: 一つ以上の取引データをまとめたものをBlockと呼ぶ。1Blockの最大容量は1MB。Bitcoinのメインネットワークでは約10分にひとつ新しいBlockが生成される。

Blockchain: Blockのつながりを指すが、Bitcoinを支える分散型台帳技術を指したり、ネットワークやソフトウェアをさすこともある。ソフトウェアはC++で開発されている。URLは下記。

GitHub - bitcoin/bitcoin: Bitcoin Core integration/staging tree

P2P(Peer to Peer): 通信技術のひとつ。対等の者同士が通信を行うモデル。通信者はサーバーにもクライアントにもなる。BlockchainはP2P通信モデルを利用している。Bitcoinのネットワークに参加したマシンは過去の全ての取引履歴(Blockchain)を主記憶装置に保存する。取引履歴のデータ容量は2017年2月の時点で、Test Networkが40GB程度、Main Networkは100GBほどある。

Blockの高さ: あるBlockが何番目に生成されたかを高さで表す。

Main/Test Network: Bitcoinには本番用とテスト用の複数のネットワークがある。やりとりする全てのメッセージの先頭4byteにMagic Valueをつけてネットワークを識別する。実際の値は下記の通り。

f:id:bambinya:20170225153554p:plain

Protocol documentation - Bitcoin Wiki )

ソースではこのあたりがネットワークのマジックナンバー。(リトルエンディアンで送られる)

https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp#L110

 

Node: Bitcoin Network参加者のこと。

アドレス: ビットコイン送信先。メールアドレスのようなもの。全てのノードが全ての取引履歴を見ることができるため、取引履歴を知られないために、通常は取引毎にアドレスを発行する。

BTC: Bitcoinの量を表す単位。

Satoshi: Bitcoinの量を表す単位。1 BTC = 100,000,000 Satoshi

Wallet: 発行したアドレスと、アドレスに紐づくぷ秘密鍵を管理する仕組み。秘密鍵の情報はwallet.datファイルに収められる。同様にBitcoin Networkで秘密鍵の管理とトランザクションを作成するクライアントソフトウェアを指すこともある。

Transaction: 取引ごとにユーザーが発行するもの。Txと書くこともある。Bitcoinがどのアドレスからいくら来て、どのアドレスにいくら行くのかという情報を持つ。データ構造は下記の通り。

f:id:bambinya:20170225172850p:plain

Transaction - Bitcoin Wiki )

ユーザーがどこからBitcoinを受け取ったかという情報はTxin、どこへ送るかという情報はTxoutに書き込まれる。lock_timeにはUnix Timeかブロックの高さを指定できる。時間が指定された場合は、マイナーが指定時間を過ぎないとtransactionをBlockに含めることができない。ブロックの高さも同様に、指定したブロックの高さにならないと、マイナーがTransactionをBlockに含められない。

UTXO(Unspent Tx Output): 未使用のBitcoin。ネットワークに参加するノードは基本的にネットワーク上の全てのUTXOをDBに保存している。Transactionに含まれるTxinで、まだ支払いに利用されていない(Txoutになっていない)BitcoinをUTXOという。

Fee: 送金にかかる手数料。Transactionのデータサイズは1byteあたり1Satoshiかかるのが相場。

Mining: Transactionの記録をBlockに追加し、新しいBlockの生成を試みること。生成に成功すると報酬としてBlockが含むTransactionの手数料の総額と成功報酬として12.5 bitcoin(2017年2月)を手に入れることができる。成功報酬の額は210,000 blocks置きに半額になる。

BIP(Bitcoin Improvement Proposals): Bitcoinの情報や新機能についてまとめた文書。Bitcoinに関するアイデアを話し合う手段として標準化されている。BIPは3種類に分けられる。

  • Standards Track BIPs - Bitcoin実装の多く、または全てに影響があるもの。またBitcoinを使うアプリケーションに影響があるもの。ネットワークプロトコルの変更や、ブロックとトランザクションのバリデーションルールの変更などが該当する。
  • Informational BIPs - デザインに関するもの、一般的なガイドライン。このタイプのBIPは新機能の提案でもコミュニティの合意を示すものでもない。BitcoinユーザーとBitcoinの開発者は自由にInformational BIPsを無視したり、アドバイスに従って良い。
  • Process BIPs - Bitcoinの実装以外に関する提案。何か実装を提案するかもしれないが、Bitcoinのcodebaseへの提案ではない。コミュニティの意思決定プロセスの変更、ガイドラインBitcoinの開発環境・ツールの提案がこのタイプに当てはまる。

bips/bip-0001.mediawiki at master · bitcoin/bips · GitHub )

Merkle Tree: データ構造のひとつ。複数のTransactionをひとつのBlockに追加するときに使う。下記の図ではMerkle Treeを利用して、Tx0からTx3のハッシュを作成し、Block Headerに追加している。

f:id:bambinya:20170225183527p:plain

https://bitcoin.org/bitcoin.pdf )

Target: Block生成時にMinersが目標とする256bitの数字。数字自体に意味はなく、2週間ごとに値が変わる。ブロックの生成は、hash関数に直前のBlockのhash値と、Blockに含めるTransactionのMerkle Treeのハッシュと、nonce(4-byteの意味を持たない数字)を入れて、関数の返り値がターゲットより小さくなるnonceを見つけることである。nonceはnumber used once(一度使われる数字)という意味。例えばターゲットが0x00000000FFFF000000......00000(64桁)ならば、hash関数に直前のBlockのhash値と、Blockに含めるTransactionのハッシュと、適当なnonceを入れ、返り値がターゲットより小さくなるようなnonceを見つければ、Blockの生成に成功したことになる。

Difficulty: あるネットワークでブロックを作る難しさをDifficultyで表す。値が高いほど、Blockの生成が難しい。値は最大ターゲット ÷ 現在のターゲットで求められる。Test NetworkではBlockが10分に1つ作られるよう、2週間に一度値が更新される。

 

参考資料

https://bitcoin.org/bitcoin.pdf (Satoshi Nakamotoが発表したオリジナル論文。情報は古い。シンプルなのでそんなに難しくない)

Bitcoin Wiki (少し情報が古い)

 

 

アルゴリズムを評価する計算量について

アルゴリズムを評価できるように、計算量(ランダウの記号)について調べた。

 

アルゴリズムの評価

アルゴリズムは、実行に必要な資源の量で評価される。

資源とは、実行にかかる時間と使用するメモリ領域を指す。一般的には資源が少ない方が評価が高いが、計算量を優先すると可読性が下がり、保守がしづらくなる。ライブラリや言語などの閲覧頻度が低く、処理速度を求められるものは計算量を優先する。アルゴリズムの用途によって決める。

 

計算量を優先したアルゴリズムの例(消費メモリは少ないが、理解に時間がかかる)

ある文字列が、すべてユニークである(重複する文字がない)かどうかを判定するアルゴリズ ...

 

計算量の種類

計算量は2種類ある。

時間計算量(Time Complexity)は、アルゴリズムが処理を終えるまでに実行する命令数(ステップ数)を表す。

領域(空間)計算量(Space Complexity)は、アルゴリズムが処理を終えるのに必要なメモリ領域を表す。

 

ランダウの記号

計算量の評価にはランダウの記号(Landau Symbol)を用いる。アルゴリズムの入力値のサイズが変化したとき、使われる資源の変化率を表す。

ランダウの記号は O (オー)記法(Big  O  Notation)とも呼ばれる。記号 O はOrder(程度)の O

一般的に O 記法は、関数の変数(この場合は入力値のサイズ)が無限に近づいたときの資源の増加率を提示する。そのため、ハードウェア依存の定数項と増加率が低い低次数の項は考慮しない。

例) あるアルゴリズムが、与えられたサイズ n のデータを処理をするのにかかる時間が次の多項式で表現できる場合、計算量は O(n^2) である。

 f(n) = 4n^2 - 2n + 2

 f(n) = O(n^2)

 

やってみよう

実際にアルゴリズムの計算量を考えてみよう。

isUniqueChar(String word)は、ある文字列がすべてユニークであるかどうか(重複する文字がないか)を判定する。

ある文字列が、すべてユニークである(重複する文字がない)かどうかを判定するアルゴリズ ...

時間計算量を考える時は、ステップ数をカウントする。そこから入力サイズ(引数wordの大きさ)に関係のあるfor文の実行回数のみ取り出す。wordの文字数分、for文が回るので時間計算量は O(n) となる。

空間計算量を考えるときは入力値の大きさは考慮しない。アルゴリズムの評価をするために、アルゴリズムが問題を解決するために必要なメモリ領域のみ考える。

isUniqueChar(String word)ではboolean[] char_set と int i とint len と int val がメモリを使用する、これらはマシンの性能や言語の型の設計に依存するため、入力値の大きさにかかわらず一定である。

よって空間計算量は  O(1) となる。

 

 

実際にかかる時間を想像してみよう

CPUは私たちが書いたアルゴリズムをどのくらいのスピードで処理するのだろうか。

代表的なCPUは1つの命令を4つのステージに分けて実行する。1ステージを実行するのに1クロックかかるので、1命令を実行するのに4クロックかかる。

(1) 命令フェッチ ; 命令コードをメモリから読み込む

(2) 命令デコード ; 読み込んだ命令コードを解析し、実行の準備を行う

(3) 実行     ; CPU内部の演算ユニットで命令を実行する

(4) ライトバック ; 実行結果をレジスタやメモリに書き込む

 

iPhone7が使用しているCPUを例にアルゴリズムが処理を終えるまでにかかる時間を想像してみる。iPhone7のCPUはARMアーキテクチャApple A10を使用している。

ARMはRISC(Reduced Instruction Set Computer)プロセッサの1つである。RISCは1つの命令を実行するステージ数とパイプラインの数を揃えることで、見かけ上1クロックあたり1命令を実行する。

f:id:bambinya:20170126171057p:plain

上の画像は、1つの命令を { IF = 命令フェッチ、ID = 命令デコード、EX = 実行、MEM = メモリアクセス、WB = レジスタ・ライトバック } の5つのステージに分けて、5つのパイプラインで5つの命令を同時実行する。実質1クロックで1命令完了することになる。

1命令をいくつのステージで実行するかは、CPUによって異なる。(Apple A10のステージ数とパイプライン数は調べたけど分からなかった)

Apple A10の動作周波数は最大で2.34GHzなので、1秒間に2,340,000,000回のクロックを刻む。ARMアーキテクチャは1クロックあたり1命令を実行するため、1秒間に2,340,000,000命令実行する。またコア数は4つなので、理論上は1秒間に9.36G回の命令を実行する。

ものすごくシンプルに考えると10,000ステップのアルゴリズムをCPUが処理する時間は、 1000 \times \frac{10000}{2.34 \times 10^9} = 0.0042..ミリ秒となる。

ただし、実際プログラムの実行には、CPUがメインメモリ、ブリッジ、ハードディスク等と情報のやり取りを行う時間(データバス)、キャッシュメモリにキャッシュがあるかどうか、命令セットの最適化、などが時間に関係し、もっと時間がかかる。この辺りは知識が全くないので、いつか検証したい。

 

参考

f:id:bambinya:20170126213048g:plain

パソコンの基礎知識 > CPU > キャッシュメモリの仕組み

RISC - Wikipedia

命令パイプライン - Wikipedia

Q&Aで学ぶマイコン講座(1):CISCとRISC、何が違う? (2/3) - EDN Japan