11

バックグラウンドスレッドでいくつかの計算作業があり、その後、いくつかのcalayerの変換を更新する必要があります。使用してみます

dispatch_async(dispatch_get_main_queue(), ^{calayer.transform = newTransform});

CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^(void) {calayer.transform = newTransform});

私はそれらが同じだと思っていましたが、dispatch_asyncを使用すると、calayerが非常にスムーズに(おそらく?)動作することがわかりました。これら2つの機能の違いは何ですか?

4

4 に答える 4

19

ここでの主な違いはCFRunLoopPerformBlock、ブロックを実行する特定の実行ループモードを指定できるのに対しdispatch_async(dispatch_get_main_queue(),...)、コモンモードでのみ実行されることです。おそらく、あなたが見ているパフォーマンスの問題に対してより適切であり、メインスレッドをウェイクアップCFRunLoopPerformBlockしません。のドキュメントからCFRunLoopPerformBlock

このメソッドはブロックのみをエンキューし、指定された実行ループを自動的にウェイクアップしません。したがって、ブロックの実行は、次に実行ループがウェイクアップして別の入力ソースを処理するときに発生します。作業をすぐに実行したい場合は、CFRunLoopWakeUp関数を使用してそのスレッドを明示的にウェイクアップする必要があります。

実際には、これは通常、実行ループがウェイクアップするまで(つまり、ユーザーイベントの発生、タイマーの起動、実行ループのソースの起動、マッハメッセージの受信など)ブロックが実行されないことを意味します。GCDは、設計上、実行ループベースのAPI。メインキューとメインスレッドの実行ループの関係は、事実上、実装の詳細です。メインキューを処理するために必要な場合は、実装が実行ループ自体をウェイクアップすることを期待します。

それとは反対の情報がないので、これがパフォーマンスの違いの原因であると強く思います。CFRunLoopWakeUpへの呼び出しの直後にへの呼び出しを追加した場合、パフォーマンスは同様になると思いますCFRunLoopPerformBlock

于 2013-02-10T19:07:13.077 に答える
7

GCD のメイン キューはシリアル キューです。そのため、一度に 1 つのタスクしか実行できません。そのタスクが内部実行ループを実行する場合 (たとえば、モーダル ダイアログを実行する場合) であっても、メイン キューに送信された他のタスクはそれが完了するまで実行できません。

を使用してサブミットされたタスクはCFRunLoopPerformBlock()、実行ループがいずれかのターゲット モードで実行されるたびに実行できます。これには、 を使用して送信されたタスク内から実行ループが実行された場合も含まれますCFRunLoopPerformBlock()

次の例を検討してください。

CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
    printf("outer task milestone 1\n");
    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
        printf("inner task\n");
    });
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    printf("outer task milestone 2\n");
});

次のような出力が生成されます。

outer task milestone 1
inner task
outer task milestone 2

これの間:

dispatch_async(dispatch_get_main_queue(), ^{
    printf("outer task milestone 1\n");
    dispatch_async(dispatch_get_main_queue(), ^{
        printf("inner task\n");
    });
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    printf("outer task milestone 2\n");
});

生成:

outer task milestone 1
outer task milestone 2
inner task
于 2014-10-02T22:49:57.320 に答える