4

まったく同じことのように見えるトピックがかなりあることは知っていますが、本当に私が望んでいたことに関するトピックは見つかりませんでした.

そこで、私は興味があり、Fast Enumeration のパフォーマンスを NSEnumerator および for ループと比較したいと考えました。(よく聞かれる部分です)

まず、高速列挙を比較しました。

for(NSNumber *number in testArray)
{
    assert(number);
}

NSEnumerator:

NSEnumerator *enumerator = [testArray objectEnumerator];
NSNumber *number;
while (number = [enumerator nextObject]) 
{
    assert(number);
}

ループの場合:

for(NSUInteger i = 0; i < [testArray count]; i++)
{
    NSNumber *number = [testArray objectAtIndex:i];
    assert(number);
}

testArrayは 0 から 1,000,000 までの NSNumbers で構成される配列で、テストを 100 回ずつ実行し、各テストの平均実行時間を計算しました。

また、iPad 2で実行しました

結果: (全 100 回の実行の平均時間)

  • 0.042687 秒の高速列挙
  • 0.582072s NSEnumerator
  • 0.627318 秒の for ループ

予想どおり、Fast Enumeration は群を抜いて最速であり、NSEnumerator は for ループよりも少し高速ですが、これは大きな配列を列挙するためのものでした。

では、あまり頻繁ではない質問を次に示します。

実際、私は別のことに興味がありました: 配列内の各オブジェクトを互いに比較するための配列内の列挙

ネストされた for ループでの最初の試行:

for(int i = 0; i < [testArray count]-1; i++)
{
    NSNumber *number = [testArray objectAtIndex:i];
    for(int j = i+1; j < [testArray count]; j++)
    {
        NSNumber *innerLoopNumber = [testArray objectAtIndex:j];
        assert(innerLoopNumber);
        assert(number);
    }
}

これらのテストでは、配列のサイズと実行回数を減らして妥当な時間内に実行する必要がありました。これは、繰り返し回数が当然 O(n^2) で増加するためです。そこで、5.000 NSNumbers の配列でそれらを実行し、テストを 5 回繰り返しました。

結果: 1 回の実行で7.360645 秒

だから私は、確かに、速い列挙はもっと速いはずだと思った。しかし、要素の各ペアを 2 回比較することを避けるために三角形のパターンを実現するには、外側のループの Fast Enumeration と内側のループの NSEnumerator を混在させる必要がありました。

for(NSNumber *number in testArray)
{
    NSEnumerator *reverseEnumterator = [testArray reverseObjectEnumerator];
    NSNumber *innerLoopNumber = reverseEnumterator.nextObject;
    while(innerLoopNumber && ![innerLoopNumber isEqualToNumber:number])
    {
        innerLoopNumber = reverseEnumterator.nextObject;
        assert(innerLoopNumber);
        assert(number);
    }
}

そして驚いたことに、これはずっと遅かった: 1 回の実行で18.086980 秒

次に、外側のループに Fast Enumeration を使用し、内側のループに for ループを使用して、ハイブリッド バージョンも試しました。

int counter = 0;
for(NSNumber *number in testArray)
{
    for(int j = counter +1; j < [testArray count]; j++)
    {
        NSNumber *innerLoopNumber = [testArray objectAtIndex:j];
        assert(innerLoopNumber);
        assert(number);
    }
    counter++;
}

結果: 1 回の実行で7.079600 秒

単純な for ループよりもわずかに高速です。

数字を 1 か所に:

  • 07.360645 秒の for ループ
  • 07.079600sハイブリッド
  • 18.086980s高速列挙

だから、それはなぜだろうか?高速列挙は「中断されていない」場合にのみうまく機能しますか? NSEnumerator の使用は高速列挙に干渉しますか? それとも、何かが足りないだけで、メソッドが間違っていますか?

4

1 に答える 1

3

高速列挙ループで追加のメソッドを呼び出しています。Objective-c には重要なメソッド呼び出しのオーバーヘッドがあるため、ネストされたループのセットアップに問題があります。ご覧のとおり、高速列挙 + for ループは for ループ + for ループよりも高速であり、ここでは追加のメソッド呼び出しを回避しています。

于 2012-07-11T13:48:39.693 に答える