3

AppBundleにXMLが含まれています。このXMLファイルを解析しています。NSXMLParser次の方法を使用して、このXMLを解析しました。

  1. コード全体をメインスレッドでシリアルに実行する
  2. ディスパッチキュー(GCD)の使用:

    2.1dispatch_queue_createを使用して独自のディスパッチキューを作成する

    2.2優先度の高いdispatch_get_global_queueでグローバルキューを使用する

    2.3優先度の低いグローバルキューの使用

    2.4バックグラウンド優先でグローバルキューを使用する

  3. を使用してNSOperationQueue

XMLファイルの解析の実行にかかったパフォーマンスと合計時間を確認したところ、非常に奇妙な(または正しい可能性がある)結果が見つかりました。

上記の解析方法のコードは次のとおりです。

  1. メインスレッドでのシリアル実行-実行時間34ミリ秒。

    BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error];
    if (success) {
        DLog(@"Parsing Complete");
    }
    else
        DLog(@"Parse error %@",[error description]);
    

2.1dispatch_queue_createの使用-実行時間68ミリ

dispatch_queue_t backgroundQueue = dispatch_queue_create("BackQueue", NULL);

dispatch_async(backgroundQueue, ^{
    NSError *error = nil;
    BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error];
    if (success) {
        DLog(@"Parsing Complete");
    }
    else
        DLog(@"Parse error %@",[error description]);
});

dispatch_release(backgroundQueue);

2.2優先度の高いdispatch_get_global_queueでグローバルキューを使用する-実行時間-74ミリ秒

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

dispatch_async(backgroundQueue, ^{
    NSError *error = nil;
    BOOL success = [conf parseXMLFile:[[NSBundle mainBundle] pathForResource:@"Configuration" ofType:@"xml"] didFailWithError:&error];
    if (success) {
        DLog(@"Parsing Complete");
    }
    else
        DLog(@"Parse error %@",[error description]);
});

dispatch_release(backgroundQueue);

2.32.2と同様に優先度が低いグローバルキューの使用DISPATCH_QUEUE_PRIORITY_LOW-実行時間-72ミリ秒

2.42.2と同様にバックグラウンド優先度でグローバルキューを使用するDISPATCH_QUEUE_PRIORITY_BACKGROUND-実行時間-37ミリ秒

2.5。使用NSOperationQueue(NSOperationのサブクラス化)-実行時間-36ミリ秒

誰かが私がこれらの実行時間を理解するのを手伝ってくれますか、そしてなぜそれらはとても奇妙なのですか(または私は何かを逃していますか)。メソッド1で最高のパフォーマンスが得られる理由DISPATCH_QUEUE_PRIORITY_BACKGROUNDがHIGHよりも優れたパフォーマンスを提供するのはなぜですか。NSOperationQueueがGCDよりも優れた結果をもたらすのはなぜですか?

4

2 に答える 2

6

アップデート:

次の2つのシナリオで、さまざまなディスパッチキューと操作キューをテストしました。

  1. 大きな(725kb)XMLファイルを1回の操作で100回繰り返し解析する単一のジョブを呼び出します。と

  2. 100個の操作をキューに入れて、同じ非常に大きなXMLファイルを1回ずつ解析します。

iPhone 5での私の結果(秒単位で測定)は次のとおりです。

  1. 最初のシナリオの場合:

    メインキュー:18.7
    NSOperation:18.4
    グローバル優先度キュー:18.3
    グローバルデフォルト優先キュー:18.4
    グローバル低優先度キュー:18.4
    グローバルバックグラウンドキュー:18.5
    シリアルディスパッチキュー:18.3
    
  2. 私の2番目のシナリオの場合:

    メインキュー:18.7
    NSOperation:10.9
    グローバル優先度キュー:10.9
    グローバルデフォルト優先キュー:10.8
    グローバル低優先度キュー:10.8
    グローバルバックグラウンドキュー:11.0
    シリアルディスパッチキュー:18.5
    

したがって、私はこれから2つのかなり驚くべき結論を導き出します。

  • 少なくとも計算量の多いバックグラウンド操作の場合、さまざまな同時バックグラウンド手法間で大きな違いは見られませんでした。

  • タスクを複数の操作に分割する場合、同時バックグラウンド操作(NSOperationQueue、GCDグローバルキュー)は、シリアル操作よりもパフォーマンスが優れていました。

ただし、リソース競合中のデバイスがスケジューリングに関して異なる動作を示さない可能性があることを示唆しているわけではありません(特に、GCDグローバルキュータイプを参照してくださいdispatch_queue_priority_t。デバイスでキューに入れられた他の同時操作との操作のスケジュールに影響します)。私は、さまざまなキューが互いに大幅に効率的または効率的ではないことを経験的に実証しようとしているだけです。DISPATCH_QUEUE_PRIORITY_HIGHそうは言っても、 iOSのコア機能に影響を与える可能性があると思うので、個人的にはアプリで使用しません。

また、完全な開示のために、私は重要なパフォーマンスの違いに焦点を合わせていることを認めなければなりません。あるメカニズムまたは別のメカニズムがミリ秒単位で測定されたパフォーマンスの違いを提供する可能性は十分にあります。バックグラウンドパフォーマンスのさまざまなアプローチを検討しているときは、ユーザーが観察できるパフォーマンスの違いに間違いなく焦点を当てています。


元の回答:

parseManyTimesメインキューから(大きなXMLファイルを繰り返し解析する)自分を呼び出しました:

[self parseManyTimes:@"Main queue"];

経由NSOperation

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
     [self parseManyTimes:@"NSOperation"];
}];
queue = nil;

GCDのグローバルキュー経由:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_DEFAULT"];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_HIGH"];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    [self parseManyTimes:@"DISPATCH_QUEUE_PRIORITY_LOW"];
});

およびGCDシリアルキュー経由:

dispatch_queue_t dispatchQueue = dispatch_queue_create("org.rob.test", NULL);
dispatch_async(dispatchQueue, ^{
    [self parseManyTimes:@"dispatch_queue_create"];
});

結果は互いに大きく異ならなかった(すべて32.2秒から32.5秒の間)。私の解析ルーチンは次のとおりです。

- (void)parseManyTimes:(NSString *)type
{
    NSDate *startDate = [NSDate date];
    for (NSInteger i = 0; i < 100; i++)
        [self parse];

    NSLog(@"%@: %.1f", type, [[NSDate date] timeIntervalSinceDate:startDate]);
}

- (void)parse
{
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"personnel" withExtension:@"xml"];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    parser.delegate = self;
    [parser parse];
}

私はこれをiPadで725kbのXMLファイルで実行しました。明らかに、私がこれを構造化した方法では、非常に時間のかかるプロセスで、さまざまなキューのディスパッチ方法にごくわずかな差異がない傾向がありますが、バックグラウンド操作に焦点を当てています。それによって、さまざまな手法でのマテリアルパフォーマンスの問題について(少なくとも私にとっては)懸念は生じません。

結果は次のとおりです。

メインキュー:32.3
NSOperation:32.2
DISPATCH_QUEUE_PRIORITY_DEFAULT:32.4
DISPATCH_QUEUE_PRIORITY_HIGH:32.3
DISPATCH_QUEUE_PRIORITY_LOW:32.5
dispatch_queue_create:32.3
于 2012-12-18T07:59:30.693 に答える
3

さまざまなデフォルトの並行キューのパフォーマンスは相対的なものにすぎません。「高い」優先度は、他のキューよりも高いことを意味します。合成ベンチマークについては、当時は他にほとんど何も起こっていなかったと思います。したがって、すべてのキューが同等に機能しているように見えるのはなぜですか。重み付けの実際のデモンストレーションが必要な場合は、100個の解析操作を並行キューに一度にエンキューし、それらの実行時間を比較します。

また、NSOperationはデフォルト優先の並行キューを使用して実行するため、パフォーマンスは基本的に同じであることがわかります。せいぜい、NSOperationのオーバーヘッドを測定しているだけです。これはごくわずかです。

最初の結果では、まったく異なるタイミングが見られました。それらの測定の条件は何でしたか?たとえば、アプリの起動時にこれを実行している場合、XML解析を別のスレッドまたはキューにシフトすると、メインスレッドとキューがCPU時間で競合する可能性があるため、時間がかかる可能性があります。この種の場合のより良いテストは、全体的な起動時間です。これは、複数のコアを利用することの利点を示します。

于 2012-12-18T20:17:39.690 に答える