2

私のコードを見直すと、多くの場所で、呼び出し[NSBlockOperationInstance start];がメインスレッドでこの操作を開始すると仮定していることに気づきました。なぜそう思ったのかはわかりませんが、そう確信する必要はありませんでした。ドキュメントを確認しましたが、ブロックが実行されるスレッドについての明示的な言及は見つかりませんでした。assert([NSThread isMainThread]);ただ、ブロック本体でのアサートは を使うたびにパスするstartので、偶然かどうかはわかりません。これがどのように機能するかをより確実に理解している人はいますか?

[op start] がメイン スレッドで呼び出されていることを忘れていました。

4

2 に答える 2

12

OK、それはすべて、start()を呼び出す場所によって異なります。NSBlockOperationはブロックを他のスレッドにファームアウトしますが、start()は同期的であり、NSBlockOperationに与えられたすべてのブロックが完了するまで戻りません。

NSBlockOperationは指定されたブロックを同時に実行しますが、NSBlockOperation自体は同時ではありません(つまり、isConcurrentはfalseです)。したがって、ドキュメントによると、start()はstart()の呼び出し元のスレッドで完全に実行されます。

start()を呼び出すスレッドは、すべてのブロックが実行されるまで戻らないため、呼び出し元のスレッドを、並行ブロックを実行しているスレッドプールに関与させることは理にかなっています。そのため、start()を呼び出したスレッドでいくつかのブロックが実行されているのがわかります。

メインスレッドでブロックが実行されているのを確認している場合は、メインスレッドからブロックを呼び出している必要があります。

関連する注意点として、NSBlockOperationに単一のブロックが含まれている場合、そのブロックは常に呼び出し元のスレッドで実行されます。

NSOperationを完全に並行させたい場合は、サブクラスに適切な機能を実装する必要があることを忘れないでください。

それを除けば、NSOperationをNSOperationQueueに与えることができ、NSOperationがキューに与えられ、操作を実行しているスレッドがstart()を呼び出すため、同時に実行されます。

個人的には、NSBlockOperationの機能を使用する必要がない限り、dispatch_async()よりもNSBlockOperationを使用することに利点はありません。1つのブロックのみを実行している場合は、

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ });

NSBlockOperationの機能を利用したいが、現在の呼び出しスレッドでそれらが完了するのを待ちたくない場合でも、これを行うのは理にかなっています...

// Add lots of concurrent blocks
[op addExecutionBlock:^{ /*whatever*/ }];
// Execute the blocks asynchronously
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [op start];
    // Now do what you want after all the concurrent blocks have completed...
    // Maybe even tell the UI
    dispatch_async(dispatch_get_main_queue(), ^{
        // Update the UI now that all my concurrent blocks have finished.
    });
});

編集 あなたのコメントをtcの答えに向けるために...

あなたが電話する場合

op = [NSBlockOperation blockOperationWithBlock:^{assert([NSThread isMainThread])}];
[op start];

メインスレッドから、いくつかの保証といくつかの高い確率があります。

まず、呼び出し元のスレッドで[opstart]が完了するまで実行されることが保証されます。これは、NSBlockOperationが、並行操作ではないことを指定するNSOperationのデフォルトの動作をオーバーライドしないためです。

次に、NSBlockOperationにブロックが1つしかない場合、呼び出し元のスレッドで実行される可能性が非常に高くなります。最初のブロックが呼び出し元のスレッドで実行される可能性はほぼ同じです。

ただし、上記の「確率」は保証ではありません(ドキュメントに記載されていないためのみ)。エンジニアの中には、その単一のブロックを並行キューの1つにスピンさせて、呼び出し元のスレッドを別のスレッドで実行されている操作に参加させる理由を見つけるかもしれないと思います...しかし、私はそれを非常に疑っています。

とにかく、おそらくあなたの混乱は、NSBlockOperationのドキュメントがブロックを同時に実行すると言っているという事実から来ています。ただし、操作自体は並行ではないため、最初の操作は同期的です。すべてのブロックが実行されるのを待ち、呼び出し元のスレッドでそれらの一部を実行する場合と実行しない場合があります。

保証はありませんが、ブロックが1つしかないNSBlockOperationが、呼び出し元のスレッドで実行する以外のことを行う可能性はほとんどありません。

于 2012-07-21T05:29:03.380 に答える
2

ドキュメントは具体的に言う

ブロック操作に追加されたブロックは、デフォルトの優先度で適切な作業キューにディスパッチされます。ブロック自体は、実行環境の構成について何の仮定もすべきではありません。

以下がクラッシュすると思われます。

NSBlockOperation * op = [NSBlockOperation blockOperationWithBlock:^{ sleep(1); }];
[op addExecutionBlock:^{assert([NSThread isMainThread]); }];
[op start];

単純にブロックを実行することの何が問題になっていますか?

于 2012-07-21T04:34:27.100 に答える