Jeter dans une autre réponse, pour essayer d'expliquer pourquoi performBlockAndWait
sera toujours exécuté dans le thread appelant.
performBlock
est complètement asynchrone. Il sera toujours de mettre en file d'attente du bloc sur la file d'attente de la réception de la MOC, et les retourner immédiatement. Ainsi,
[moc performBlock:^{
// Foo
}];
[moc performBlock:^{
// Bar
}];
fera deux blocs sur la file d'attente pour le moc. Ils vont toujours s'exécuter de manière asynchrone. Un inconnu thread va tirer des blocs de la file d'attente et de les exécuter. En outre, ces blocs sont enveloppés à l'intérieur de leur propre autorelease pool et ils représentent une complète Base de Données de l'utilisateur (processPendingChanges
).
performBlockAndWait
ne PAS utiliser la file d'attente interne. C'est une opération synchrone qui s'exécute dans le contexte du thread appelant. Bien sûr, il faudra patienter jusqu'à l'exploitation courante dans la file d'attente ont été exécutées, et alors que le bloc s'exécute dans le thread appelant. Ceci est documenté (et réaffirmé dans plusieurs WWDC présentations).
En outre, performBockAndWait
est ré-entrant, de sorte que les appels imbriqués, tout se fait à droite dans ce thread appelant.
La Base de Données ingénieurs ont été très clairs à ce que le thread dans lequel une file d'attente MOC opération s'exécute n'est pas important. C'est la synchronisation à l'aide de l' performBlock*
API c'est la clé.
Donc, envisager de performBlock " comme "Ce bloc est placé dans une file d'attente, pour être exécuté à un certain temps indéterminé, dans certains indéterminée fil. La fonction sera de retour à l'appelant dès qu'il a été mis en file d'attente"
performBlockAndWait
est "Ce bloc sera exécuté à un certain temps indéterminé, dans ce même thread. La fonction sera de retour après ce code a complètement exécuté (qui aura lieu après la file d'attente en cours associé avec ce MOC a drainé)."
MODIFIER
Êtes-vous sûr de "performBlockAndWait ne PAS utiliser la file d'attente interne"?
Je pense qu'il n'. La seule différence est que performBlockAndWait va
attendre jusqu'à ce que le bloc d'achèvement. Et qu'entendez-vous par appel
thread? Dans ma compréhension, [moc performBlockAndWait] et [moc
performBloc] tous les deux sur sa file d'attente privée (de fond ou de la main). L'
concept important ici est de moc est propriétaire de la file d'attente, pas dans l'autre sens
autour de. S'il vous plaît corrigez-moi si je me trompe. – Philip007
C'est dommage que j'ai formulée de la réponse comme je l'ai fait, parce que, prises par lui-même, il est incorrect. Cependant, dans le contexte de la question d'origine, il est correct. Plus précisément, lors de l'appel d' performBlockAndWait
sur une file d'attente privée, le bloc à exécuter dans le thread qui a appelé la fonction, il ne sera pas mis sur la file d'attente et sont exécutés sur le "private thread."
Maintenant, avant même d'entrer dans les détails, je tiens à souligner que selon le fonctionnement interne des bibliothèques est très dangereux. Tout ce que vous devriez vraiment prendre soin, c'est que vous ne peut jamais s'attendre à un thread spécifique pour l'exécution d'un bloc, à l'exception de tout autre article pour le thread principal. Ainsi, s'attendant à un performBlockAndWait
à ne pas exécuter dans le thread principal n'est pas conseillé, car il va les exécuter dans le thread qui l'a appelée.
performBlockAndWait
utilise GCD, mais il a aussi son propre calque (par exemple, pour éviter les blocages). Si vous regardez le PGCD de code (qui est open source), vous pouvez voir comment les appels synchrones de travail et, en général, ils se synchronisent avec la file d'attente et appeler le bloc sur le thread qui a appelé la fonction, à moins que la file d'attente est le principal file d'attente ou un mondial de la file d'attente. Aussi, dans la WWDC pourparlers, la Base de Données ingénieurs de souligner que les performBlockAndWait
sera exécuté dans le thread appelant.
Donc, quand je dis de ne pas utiliser la file d'attente interne, cela ne signifie pas qu'il n'utilise pas les structures de données à tous. Il doit synchroniser l'appel avec les blocs déjà dans la file d'attente, ainsi que ceux présentés dans d'autres fils et d'autres appels asynchrones. Cependant, lors de l'appel d' performBlockAndWait
il n'a pas mis le bloc sur la file d'attente... au lieu de cela il se synchronise l'accès et exécute le soumis bloc sur le thread qui a appelé la fonction.
Maintenant, ce n'est pas un bon forum pour cela, parce que c'est un peu plus complexe que cela, surtout w.r.t la file d'attente principale, et PGCD mondial des files d'attente - mais ce dernier n'est pas important pour la Base de Données.
Le point principal est que lorsque vous appelez une performBlock*
ou PGCD fonction, vous ne devriez pas attendre pour l'exécuter sur n'importe quel thread particulier (à l'exception de quelque chose lié à la thread principal) parce que les files d'attente ne sont pas les threads, et seuls les principaux file d'exécuter des blocs sur un thread spécifique.
Lors de l'appel de la base de données performBlockAndWait
le bloc s'exécute dans le thread appelant (mais sera correctement synchronisées avec tout soumis à la file d'attente).
J'espère qu'un sens, même s'il est probablement causé plus de confusion.
MODIFIER
En outre, vous pouvez voir les non-dits des implications de cela, que la façon dont performBlockAndWait
fournit à ré-entrant soutien des sauts de la FIFO de commande de blocs. Comme un exemple...
[context performBlockAndWait:^{
NSLog(@"One");
[context performBlock:^{
NSLog(@"Two");
}];
[context performBlockAndWait:^{
NSLog(@"Three");
}];
}];
Notez que le strict respect de la FIFO de garantie de la file d'attente signifie que le sous - performBlockAndWait
("Trois") courent après le asynchrones bloc ("Deux") depuis qu'il a été déposé après le bloc async a été soumis. Cependant, ce n'est pas ce qui se passe, car il serait impossible... pour la même raison, un blocage s'ensuit avec imbriqué dispatch_sync
des appels. Juste quelque chose d'être conscient de si vous utilisez la version synchrone.
En général, éviter de synchroniser les versions à chaque fois que possible, car dispatch_sync
peut provoquer un blocage, et de tout ré-entrant version, comme performBlockAndWait
aurez à faire une "mauvaise" décision de le soutenir... comme avoir la synchronisation des versions "sauter" la file d'attente.