IPhoneやその他のポータブルハードウェアでCPU集約型またはGPU集約型アプリケーションをプログラミングする場合、コードを高速化するために賢明なアルゴリズム決定を行う必要があります。
しかし、使用している言語のパフォーマンスが他の言語よりも劣っている場合、優れたアルゴリズムの選択でも時間がかかることがあります。
Objective-CとC++を比較するハードデータはありますか。具体的にはiPhoneだけでなく、Macデスクトップでも、同様のさまざまな言語のパフォーマンスを確認するためのデータはありますか?私は CとObjective-Cを比較するこの記事 に非常に精通していますが、これは2つのオブジェクト指向言語を互いに比較するというより大きな問題です。
たとえば、C++ vtableルックアップはObj-Cメッセージよりも本当に速いですか?どれくらい速いですか?スレッド、ポリモーフィズム、ソートなど。重複したオブジェクトモデルとさまざまなテストコードを使用してプロジェクトを構築するための探求に進む前に、誰かがこれをすでに行っているかどうか、結果はどこにあるかを知りたい。このタイプのテストと比較は、それ自体がプロジェクトであり、かなりの時間がかかります。たぶん、これは1つのプロジェクトではなく、2つだけの出力を比較できます。
伝道ではなく、ハードデータを探しています。多くの皆さんのように、私はさまざまな理由で両方の言語を愛しています。さらに、同じことを積極的に追求している人がいる場合は、最終結果を確認するためにいくつかのコードを提案するのが面白いでしょうし、他の人も助けになると確信しています。私の推測では、どちらにも長所と短所があり、私の目標は、それらが何であるかを正確に調べて、現実世界のシナリオで回避/活用できるようにすることです。
Mike Ashの投稿では、さまざまなObjective-Cメソッド呼び出しとCおよびC++のパフォーマンスを比較するためのハードナンバーがあります 「一般的な操作のパフォーマンス比較」 。また、Savoy Softwareによる この投稿 は、Objective-C++を使用してiPhoneアプリケーションのパフォーマンスを調整することに関して興味深い読み物です。
私はObjective-C++よりもObjective-Cの簡潔で記述的な構文を好む傾向があり、言語自体が私のパフォーマンスのボトルネックの原因ではないことを発見しました。コードのメンテナンス性が向上すると、パフォーマンスを少し犠牲にすることがわかっていることすらする傾向があります。
はい、よく書かれたC++はかなり高速です。パフォーマンスが重要なプログラムを作成していて、C++がCほど速くない(または数パーセント以内)場合は、何かが間違っています。あなたのObjC実装がCと同じくらい速い場合、何か通常が間違っています-すなわち、プログラムはおそらくObjC OODの悪い例です。直接のivarアクセスのように、内部で動作している抽象化レイヤーの下に踏み込む「ダーティ」トリック。
Mike Ashの「比較」は非常に誤解を招く恐れがあります-作成したプログラムの実行時間を比較するアプローチを推奨したり、CとC++とObjCを比較することを推奨したりすることはありません。表示される結果は、コンパイラー最適化disabledを使用したテストから提供されます。実行時間を測定している場合、最適化を無効にしてコンパイルされたプログラムはほとんど関係ありません。 C++とObjective-Cを比較するベンチマークと見なすことには欠陥があります。このテストでは、現実世界で最適化された実装全体ではなく、個々の機能も比較します。個々の機能は、両方の言語で非常に異なる方法で組み合わされます。これは、最適化された実装の現実的なパフォーマンスベンチマークとはほど遠いものです。例:最適化enabledでは、IMP
キャッシュは仮想関数呼び出しと同じくらい遅いです。静的ディスパッチ(たとえば、virtual
を使用した動的ディスパッチとは対照的に)および既知のC++型(動的ディスパッチがバイパスされる可能性がある)への呼び出しは、積極的に最適化できます。このプロセスは仮想化と呼ばれ、使用される場合、virtual
と宣言されたメンバー関数はinline
dになることさえあります。 virtual
と宣言され、空のボディを持つメンバー関数に対して多くの呼び出しが行われるマイクアッシュテストの場合:これらの呼び出しは完全に最適化されます完全にコンパイラが実装を認識し、動的ディスパッチが不要であると判断できるため、型がわかっている場合。コンパイラは、最適化されたビルド(スタックストレージを優先)でmalloc
への呼び出しを削除することもできます。そのため、C、C++、またはObjective-Cのいずれかでコンパイラーの最適化を有効にすると、実行時間に劇的な違いが生じる可能性があります。
それは、提示された結果がまったく役に立たないということではありません。あるプラットフォームまたはアーキテクチャと別のプラットフォームまたはアーキテクチャでpthread_create
または+[NSObject alloc]
に費やす時間に測定可能な差があるかどうかを判断する場合、外部APIに関する有用な情報を取得できます。もちろん、これらの2つの例では、テストで最適化された実装を使用します(偶然開発していない限り)。しかし、コンパイルしたプログラムである言語を別の言語と比較する場合、提示された結果は最適化が無効になっていると役に立ちません。
オブジェクト作成
ObjCでのオブジェクトの作成も検討してください。すべてのオブジェクトは動的に割り当てられます(ヒープ上など)。 C++では、オブジェクトはスタック上(たとえば、C構造体を作成し、多くの場合単純な関数を呼び出すのとほぼ同じ速度)、ヒープ上、または抽象データ型の要素として作成できます。割り当てて解放するたびに(たとえば、malloc/freeを介して)、ロックを導入できます。スタック上にC構造体またはC++オブジェクトを作成する場合、ロックは必要ありません(内部メンバーがヒープ割り当てを使用する場合があります)。多くの場合、わずか数命令または数命令に関数呼び出しがかかります。
同様に、ObjCオブジェクトは参照カウントインスタンスです。パフォーマンスが重要なC++でstd::shared_ptr
であるオブジェクトの実際の必要性は非常にまれです。 C++では、すべてのインスタンスを共有の参照カウントインスタンスにする必要はありません。 C++を使用すると、所有権と存続期間をより細かく制御できます。
配列とコレクション
CおよびC++の配列と多くのコレクションも、厳密に型指定されたコンテナと連続メモリを使用します。次の要素のメンバーのアドレスはよく知られているため、オプティマイザーはさらに多くのことができ、キャッシュとメモリの局所性が優れています。 ObjCでは、標準オブジェクト(たとえば、NSObject
)の現実からはほど遠いです。
発送
メソッドに関して、多くのC++実装は、特に高度に最適化されたプログラムで、仮想/動的呼び出しをほとんど使用しません。これらはオプティマイザー用の静的メソッド呼び出しと飼料です。
ObjCメソッドでは、各メソッド呼び出し(objcメッセージ送信)は動的であるため、オプティマイザーのファイアウォールになります。最終的には、パフォーマンスが重要なObjCを記述するときにパフォーマンスを最小限に抑えるためにできることとできないことに関して、多くの制限や不便が生じます。これにより、より大きなメソッド、IMPキャッシング、Cの頻繁な使用が発生する場合があります。
一部のリアルタイムアプリケーションは、レンダーパスでany ObjCメッセージングを使用できません。なし-オーディオレンダリングはこの良い例です。 ObjCディスパッチは、単にリアルタイムを目的として設計されていません。オブジェクトのメッセージング時に、背後で割り当てとロックが発生する可能性があり、objcメッセージングの複雑さ/時間を予測不能にして、オーディオレンダリングが期限を逃す可能性があります。
その他の機能
C++は、そのライブラリの多くにジェネリック/テンプレート実装も提供します。これらは非常によく最適化されます。これらはタイプセーフであり、テンプレートを使用して多くのインライン化と最適化を行うことができます(コンパイル時に行われるポリモーフィズム、最適化、および特殊化を考慮してください)。 C++は、厳密なObjCでは利用できない、または匹敵しないいくつかの機能を追加します。非常に異なる言語、オブジェクト、およびライブラリを直接比較しようとすることはそれほど有用ではありません。実際の実現の非常に小さなサブセットです。設計と実装の多くの側面を考慮して、質問をライブラリ/フレームワークまたは実際のプログラムに拡張することをお勧めします。
その他のポイント
CおよびC++シンボルは、ビルドのさまざまな段階(ストリッピング、デッドコードの除去、インライン化と早期インライン化、およびリンク時間の最適化)で簡単に削除および最適化できます。この利点には、バイナリサイズの削減、起動/ロード時間の短縮、メモリ消費量の削減などが含まれます。単一のアプリの場合、それほど大したことではないかもしれません。しかし、大量のコードを再利用する必要がある場合、ObjCを実装すると、共有ライブラリは不必要な重みをプログラムに追加する可能性があります。そのため、スケーラビリティと再利用は、中規模/大規模プロジェクト、および再利用率の高いグループの要素でもあります。
含まれるライブラリ
また、ObjCライブラリの実装者は環境に合わせて最適化するため、そのライブラリ実装者はいくつかの言語および環境機能を利用して、最適化された実装を提供できます。純粋なObjCで最適化されたプログラムを作成する場合、かなり重要な制限がありますが、Cocoaには高度に最適化された実装がいくつかあります。これはCocoaの長所の1つですが、C++標準ライブラリ(一部の人はSTLと呼んでいます)も前かがみではありません。 CocoaはC++よりもはるかに高い抽象化レベルで動作します-自分が何をしているか(または行うべきか)がよくわからない場合、金属に近い位置で操作すると実際にコストがかかります。特定の分野の専門家ではない場合、適切なライブラリの実装に頼ることは、本当に学習する準備ができていない限り、良いことです。同様に、Cocoaの環境は限られています。 OSをより有効に活用する実装/最適化を見つけることができます。
最適化されたプログラムを作成していて、C++とObjCの両方でそのような経験がある場合、cleanC++実装は、cleanObjC(はい、Cocoaと比較できます)。最適化の方法を知っていれば、多くの場合、より高いレベルの汎用抽象化よりも優れた結果を得ることができます。ただし、一部の最適化されたC++実装は、Cocoaの速度と同じかそれよりも遅くなります(たとえば、ファイルI/Oでの私の最初の試行は、Cocoaの速度よりも遅くなりました-主にC++の実装がメモリを初期化するためです)。
その多くは、使い慣れた言語機能に帰着します。私は両方の言語を使用しますが、両方とも異なる強さとモデル/パターンを持っています。それらは互いに非常によく補完し合っており、両方に優れたライブラリがあります。複雑でパフォーマンスが重要なプログラムを実装している場合、C++の機能とライブラリを正しく使用すると、より多くの制御が可能になり、最適化に大きな利点が得られます。右手では、「数倍高速」が適切なデフォルトの期待値です(毎回勝つことを期待しないでください。 C++を十分に理解して、実際にその点に達するには何年もかかります。
パフォーマンスクリティカルパスの大部分をC++として保持していますが、ObjCもいくつかの問題に対する非常に優れたソリューションであり、利用可能な非常に優れたライブラリがあることも認識しています。
誤解を招かない「ハードデータ」を収集するのは非常に困難です。
提案されているように機能間の比較を行う際の最大の問題は、2つの言語が非常に異なるコーディングスタイルを推奨することです。 Objective-Cは、一般的なC++の使用法が静的である、ダックタイピングを使用した動的言語です。同じオブジェクト指向アーキテクチャの問題には、C++またはObjective-Cを使用した非常に異なる理想的なソリューションがあります。
私の感覚(主に大規模なプロジェクトで両方の言語で多くプログラミングしているため):Objective-Cのパフォーマンスを最大化するには、Cに非常に近いところに記述する必要があります。一方、C++では、 Cと比較したパフォーマンスの低下.
どちらの方がよいですか?知りません。純粋なパフォーマンスのために、C++には常にEdgeがあります。しかし、Objective-CのOOPスタイルには間違いなくメリットがあります。まともなアーキテクチャを維持する方が簡単だと思います。
これは、言語機能の使用方法に本当に依存するため、一般的に答えられるものではありません。両方の言語には、速いもの、遅いもの、そして時々速くて時には遅いものがあります。それは本当に何を使用し、どのように使用するかに依存します。確実にする唯一の方法は、コードをプロファイルすることです。
Objective Cでは、c ++コードも記述できるため、ほとんどの場合、Objective Cでコーディングする方が簡単かもしれません。また、その中でうまく機能しないものを見つけた場合は、c ++バージョンを作成することができます。それとそれが役立つかどうかを確認します(C++はコンパイル時に最適化する傾向があります)。インターフェースのAPIも記述されている場合、Objective Cは使いやすくなります。また、スタイルOOPの方が簡単または柔軟です。
最後に、安全で堅牢なコードを記述できることがわかっているものを使用する必要があります。他の言語から特別な注意が必要な領域が見つかった場合は、それに切り替えることができます。 X-Codeでは、同じプロジェクトで両方をコンパイルできます。
Objective Cのハードデータはありませんが、C++を探すのに適した場所はあります。
C++は、C++の初期の時代を振り返ったBjarne Stroustroupによると、クラスとしてCとして始まりました( http://www2.research.att.com/~bs/hopl2.pdf ) (Objective Cのように)オブジェクト指向の限界にCを押し込むと考えてください。
それらの制限は何ですか? 1994年から1997年の時間枠で、多くの研究者は、オブジェクトの向きが動的なバインド、たとえばC++関数が仮想としてマークされ、これらの関数をオーバーライドする子クラスがある場合とない場合があります。 (JavaおよびC#では、すべての関数はアクターが本質的に仮想であることを期待しており、それに対してできることはあまりありません。)で、「Java Just-In-Timeコンパイラ」は、ウルズヘルズルとジェラルドアイグナーの1つを含む、これに対処するために使用される技術を対比しています。 C++プログラムでは平均して5.7%の時間(最大50%まで)が仮想関数(vtables +サンクなど)の呼び出しに費やされていました。彼は後に、Smalltalkの再販業者と協力してJava HotSpot VM OOでこれらの問題を解決します。これらの機能の一部はC++にバックポートされています(「保護」や例外処理など)。
前述したように、C++は、Objective Cがカモ型である静的型です。実行のパフォーマンスの違い(コード行ではない)は、おそらくこの違いの結果です。
ほぼ2年前にiPhone 3Gで行ったいくつかのテストがありますが、当時はドキュメントもハードナンバーもありませんでした。それらがどの程度有効であるかはわかりませんが、ソースコードが投稿され添付されています。
これは非常に大規模なテストではありません。主に、多数のオブジェクトを反復処理するためのNSArrayとC Arrayに興味がありました。
http://memo.tv/nsarray_vs_c_array_performance_comparison
http://memo.tv/nsarray_vs_c_array_performance_comparison_part_ii_makeobjectsperformselector
反復回数が多い場合、C配列がはるかに高速であることがわかります。それ以来、ボトルネックはおそらくNSArrayの反復ではなく、メッセージの送信であることに気付きました。 methodForSelectorを試して、メソッドを直接呼び出して、その違いがどれほど大きいかを確認したかったのですが、それには決して回りませんでした。 Mike Ashのベンチマークによると、5倍以上高速です。
この調査 はCPUを集中的に使用するゲームで実際にパフォーマンスを得るためには、Cを使用する必要があります。リンクされた記事には、実行可能なXCodeプロジェクトが含まれています。
bottom lineは次のとおりです:iPhoneの機能を操作する必要がある場所でObjective-Cを使用します(結局、 どこでもトランポリンを置くことができます '誰にとっても良い )、ただし、ループ、ベクターオブジェクトクラス、または集中的な配列アクセスなどの場合は、C++ STLまたはC配列を使用してパフォーマンスを向上させます。
つまり、position = [[Vector3 alloc] init] ;
。位置ベクトルなどの基本オブジェクトで参照カウントを使用する場合、パフォーマンスヒットを求めているだけです。