私は、objective-c のすべての条件ステートメントの違いと、どれがより速くて軽いかを知りたいだけです。
10 に答える
1 つのアドバイス: どの言語構成要素が他のどの言語構成要素より微視的に速いか遅いかを気にするのをやめ、代わりに、どの言語構成要素が自分を最もよく表現できるかに注目してください。
言語にとらわれないバージョン (ほとんどの場合、これは宣言型言語やその他の奇妙な言語には当てはまりません):
私がプログラミングを教えられたとき(かなり前のことですが、率直に認めます)、言語は命令を実行する 3 つの方法で構成されていました。
- シークエンス(順番に物事を行うこと)。
- 選択 (多くのことの 1 つを行う)。
- 反復 (何かを 0 回以上実行すること)。
if
andステートメントは、どちらも選択のcase
バリアントです。If
条件に基づいて 2 つの異なるオプションのいずれかを選択するために使用されます (疑似コードを使用)。
if condition:
do option 1
else:
do option 2
else
が必要ない場合があることに注意してくださいelse do nothing
。if
また、オプション 1 または 2 は、より多くのステートメント (ネストと呼ばれる)を含む、任意のステートメント タイプで構成される場合があることも覚えておいてください。
Case
は少し異なります。通常、キャラクターに基づいてさまざまなことをしたい場合など、2 つ以上の選択肢を意味します。
select ch:
case 'a','e','i','o','u':
print "is a vowel"
case 'y':
print "never quite sure"
default:
print "is a consonant"
2 つのオプション (または 1 つ)を使用できますがcase
、熱核弾頭でハエを殺すのと少し似ていることに注意してください。
While
選択バリアントではなく、反復バリアントです。for
、repeat
、until
およびその他の多くの可能性に属しています。
どちらが最速かは、ほとんどの場合問題になりません。コンパイラの作成者は、コードから最後のパフォーマンスを引き出す方法を、私たち人間よりもはるかによく知っています。あなたは彼らが仕事を正しく行うことを信頼するか、アセンブリで自分でコーディングします(私は前者を好みます)。
些細なことよりもマクロビューに集中することで、はるかに優れたパフォーマンスが得られます。これには、適切なアルゴリズムの選択、プロファイリング、およびホット スポットのターゲティングが含まれます。毎月 5 分かかるものを見つけて、それを 2 分で実行することはほとんど役に立ちません。毎分発生する何かを少しずつ改善する方がよいでしょう。
、などの言語構成要素はif
、頻繁に使用され、比較的単純であるため、可能な限り高速になります。最初は読みやすくするためにコードを書き、パフォーマンスが問題になったときだけ心配する必要があります (YAGNI を参照してください)。while
case
if/goto
代わりに組み合わせを使用case
すると、実行速度が少し速くなることがわかったとしても、結果として生じるソース コードの泥沼は、追跡を維持するのが難しくなります。
各条件ステートメントは異なる目的を果たし、すべての状況で同じものを使用するわけではありません。どれがどの状況に適しているかを学び、コードを記述します。コードのプロファイルを作成し、ボトルネックがあることがわかった場合は、先に進んで対処します。実際に問題が発生する前に、最適化について心配する必要はありません。
大きなループ内でif構造がswitchステートメントよりも高速に実行されるかどうかを尋ねていますか?もしそうなら、私は簡単なテストをまとめました、このコードは私が最新のXcodeとiPhoneSDKで作成したばかりの新しいビューベースのプロジェクトのviewDidLoadメソッドに入れられました:
NSLog(@"Begin loop");
NSDate *loopBegin = [NSDate date];
int ctr0, ctr1, ctr2, ctr3, moddedNumber;
ctr0 = 0;
ctr1 = 0;
ctr2 = 0;
ctr3 = 0;
for (int i = 0; i < 10000000; i++) {
moddedNumber = i % 4;
// 3.34, 1.23s in simulator
if (moddedNumber == 0)
{
ctr0++;
}
else if (moddedNumber == 1)
{
ctr1++;
}
else if (moddedNumber == 2)
{
ctr2++;
}
else if (moddedNumber == 3)
{
ctr3++;
}
// 4.11, 1.34s on iPod Touch
/*switch (moddedNumber)
{
case 0:
ctr0++;
break;
case 1:
ctr1++;
break;
case 2:
ctr2++;
break;
case 3:
ctr3++;
break;
}*/
}
NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:loopBegin];
NSLog(@"End loop: %f seconds", elapsed );
このコードサンプルは完全ではありません。先に指摘したように、他のコードサンプルよりも頻繁に発生する状況がある場合は、もちろん、比較の総数を減らすために、そのコードサンプルを前もって配置する必要があります。それは、決定がブランチ間で多かれ少なかれ均等に分割されている状況で、if構造が少し速く実行されることを示しています。
また、この小さなテストの結果は、デバイスで実行する場合とエミュレータで実行する場合でパフォーマンスが大きく異なることに注意してください。コードコメントで引用されている時間は、実際のデバイスで実行されています。(最初に表示されるのは、コードが最初に実行されたときにループを実行した時間であり、2番目の数値は、再構築せずに同じコードを再度実行したときです。)
while は条件式ではなく、ループです。違いは、while ループの本体は何度も実行でき、条件の本体は 1 回だけ実行されるか、まったく実行されないことです。
if と switch の違いは、if は条件として任意の式を受け入れ、switch は比較対象の値を取るだけであるということです。基本的に、 のような構造がある場合if(x==0) {} else if(x==1) {} else if(x==2) ...
、switch を使用すると、より簡潔に (そして効果的に) 記述できます。
ケースステートメントは次のように書くことができます
if (a)
{
// Do something
}
else if (b)
{
// Do something else
}
しかし、ケースは条件を 1 回だけ評価してから分岐するため、はるかに効率的です。
while
条件を評価し、関連するコード ブロックを複数回実行する場合にのみ役立ちます。条件が 1 回だけ発生すると予想される場合は、 と同等if
です。より適切な比較はwhile
、より一般化されfor
た .
条件文と条件ループがあります。(ウィキペディアが信頼できるものである場合、プログラミングで単に「条件付き」と呼ぶことは条件付きループをカバーしません。しかし、これはマイナーな用語の問題です。)
Shmooptyは、「これらのステートメントは異なることを行うので、どちらが速いかを議論することは無意味です」と述べました。
ええと...それは不十分に費やされた時間かもしれませんが、それは無意味ではありません。たとえば、次のif
ステートメントがあるとします。
if (cond) {
code
}
これを、最大で1回実行されるループに変換できます。
while (cond) {
code
break;
}
if
後者は、ほとんどすべての言語で遅くなります(または、オプティマイザーが舞台裏で元の言語に戻したため、同じ速度になります!)それでも、コンピュータープログラミングでは、(奇妙な状況のために)複雑なものが速く実行される場合があります
しかし、それらの事件はごくわずかであり、その間にあります。コードに焦点を当てる必要があります。コードを最も明確にするものと、意図を捉えるものです。
ループと分岐を簡単に説明するのは困難です。C スタイル言語で構成要素から最適なコードを取得するには、使用するプロセッサとコードのローカル コンテキストに依存します。主な目的は、主に分岐予測ミスを減らすことによって、実行パイプラインの中断を減らすことです。
すべての最適化のニーズについては、ここにアクセスすることをお勧めします。マニュアルは C スタイルのプログラマー向けに書かれており、アセンブリの知識があれば比較的簡単に理解できます。これらのマニュアルでは、最新のプロセッサの微妙な点、トップ コンパイラが使用する戦略、およびコードを最大限に活用するための最適な構造化方法について説明する必要があります。
条件と分岐コードについて最も重要なことを思い出しました。次のようにコードを注文します
if(x==1); //80% of the time
else if(x==2); // 10% of the time
else if(x==3); //6% of the time
else break;
else シーケンスを使用する必要があります... この場合、CPU の予測ロジックは正しく予測しx==1
、すべての実行の 80% でパイプラインの中断を回避します。
インテルからの詳細情報。特に:
これらのルールを利用するコードを効果的に作成するには、if-else ステートメントまたは switch ステートメントを作成するときに、最も一般的なケースを最初に確認し、最も一般的でないケースまで段階的に作業を進めます。通常、ループ反復子の条件のみが使用されるため、ループでは、静的分岐予測のためにコードの特別な順序付けは必ずしも必要ではありません。
このルールに従うことで、チェーンされた条件に対して予測ロジックをバイアスする方法について、CPU にヒントを与えることができます。