web-dev-qa-db-fra.com

Quelle est la différence entre les appels synchrones et asynchrones dans Objective-C, par rapport au multi-threading?

Pendant très longtemps, j'ai pensé que l'asynchrone était synonyme d'exécuter quelque chose sur un thread en arrière-plan, alors que synchrone signifiait sur le thread principal (blocage des mises à jour et des interactions de l'interface utilisateur). Je comprends que ne pas exécuter sur le thread principal des actions coûteuses est dû au fait que cela ne permet pas aux actions de l'interface utilisateur de se produire tant que le thread principal est occupé, mais pourquoi les problèmes de synchronisation sont-ils gênants?

Cependant, il m’est venu à mon attention que vous pouvez effectuer des appels asynchrones sur le thread principal et des appels synchrones sur des threads en arrière-plan.

J'entends toujours les gens dire de ne pas utiliser d'appels coûteux de manière synchrone ou sur le fil principal, car cela bloquerait l'interface utilisateur pour l'utilisateur. S'agit-il de deux problèmes distincts que je devrais m'assurer de ne pas faire? Quelles sont les différences?

52
Doug Smith

Lorsque vous appelez quelque chose de manière synchrone, cela signifie que le thread qui a initié cette opération attendra que la tâche se termine avant de continuer. Asynchrone signifie qu’il n’attendra pas.

Cela dit, lorsque des personnes vous suggèrent d'exécuter un processus lent ou coûteux de manière asynchrone, elles suggèrent implicitement non seulement d'exécuter le processus de manière asynchrone, mais également de le faire sur un thread en arrière-plan. L'objectif est de libérer le thread principal afin qu'il puisse continuer à répondre à l'interface utilisateur (plutôt que de geler), de sorte que vous distribuez des tâches à un thread en arrière-plan de manière asynchrone.

Donc, il y a deux parties à cela. Tout d’abord, en prenant GCD comme exemple, vous récupérez une file d’arrière-plan (vous devez soit saisir l’une des files d’arrière-plan globales, soit créer la vôtre):

// one of the global concurrent background queues

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// or you could create your own serial background queue:
//
// dispatch_queue_t queue = dispatch_queue_create("com.domain.app.queuename", 0);

Deuxièmement, vous répartissez vos tâches dans cette file d'attente de manière asynchrone:

dispatch_async(queue, ^{
    // the slow stuff to be done in the background
});

Le modèle des files d’opération est très similaire. Créez une file d'attente d'opérations et ajoutez des opérations à cette file d'attente.

En réalité, la distinction synchrone vs asynchrone est complètement différente de la distinction entre file principale et file d’arrière-plan. Mais lorsque les gens parlent de "exécuter un processus lent de manière asynchrone", ils disent en réalité "exécuter un processus lent de manière asynchrone dans une file d'attente en arrière-plan".

102
Rob

"Synchrone" signifie essentiellement "dans l'ordre" En principe, lorsque vous effectuez une opération synchrone, tout ce qui vient plus tard doit attendre que l'opération se termine avant de pouvoir commencer.

Inversement, "asynchrone" plus ou moins signifie "pas dans l'ordre." Lorsque vous faites quelque chose de manière asynchrone, le code suivant peut être immédiatement exécuté et l'opération asynchrone sera exécutée… de temps en temps. . Il peut être exécuté en parallèle avec le reste du code sur un autre thread. Il pourrait simplement être programmé pour une autre fois sur le même fil.

Le concept de synchronicité n'a rien à voir avec des fils particuliers, en soi. Il s'agit simplement de savoir si vous devez attendre qu'une opération se termine ou non.

Les programmes Cocoa (Touch) constituent le fil conducteur de ce processus. AppKit exécute la boucle d'événements principale sur le thread principal. Par conséquent, si le thread principal attend la fin d'une opération, il ne peut traiter aucune entrée ni mettre à jour l'interface utilisateur. Si vous avez un morceau de code exécuté sur un thread d’arrière-plan, l’exécution de code synchrone ne bloquera pas la boucle principale de l’événement , car ce n’est pas le cas. thread principal en attente de l'opération synchrone.

De même, une longue opération asynchrone à partir d'un thread en arrière-plan que vous placez sur le thread principal peut causer des problèmes, car tant que le thread en arrière-plan ne va pas pour attendre la fin de l'opération, il faut encore du temps sur le thread principal où la boucle d'événements doit être exécutée.

27
Chuck

Prenons quelques exemples simples:

Appel asynchrone avec multithreading:

 // La méthode est appelée dans un autre thread et ne bloque pas le thread actuel. 
 [NSURLConnection sendAsynchronousRequest: demande 
 File d'attente: file d'attente 
 D'achèvement: -. }]; 

Appel synchrone avec multithreading:

 // Faites quelque chose 
 Dispatch_sync (file d'attente, ^ {
 // faites quelque chose d'autre 
}); 
 // Faites plus de choses 
 

Ici, vous avez // Faites quelque chose // Faites quelque chose d'autre et // Faites plus de choses effectuées consécutivement même si // Faites autre chose est fait sur un autre thread.

Habituellement, lorsque les utilisateurs utilisent des threads différents, l'objectif est que quelque chose puisse être exécuté sans attendre. Supposons que vous souhaitiez télécharger une grande quantité de données, mais que vous souhaitiez que l'interface utilisateur reste fluide.

Ainsi, dispatch_sync est rarement utilisé. Mais c'est là. Personnellement, je n'ai jamais utilisé cela. Pourquoi ne pas demander un exemple de code ou un projet utilisant dispatch_sync.

Appel asynchrone avec un thread:

 [auto-performantSelector: @selector (doSomething) withObject: nil afterDelay: 0]; 

Ici, le cycle d'exécution actuel doit être terminé avant que "quelque chose" ne soit appelé. En d'autres termes, la pile d'appels en cours peut être complétée (la méthode en cours est renvoyée) avant l'appel de "quelque chose".

Appel synchrone avec un thread:

 [auto faire quelque chose]; 

Je ne pense pas que vous ayez besoin d'explication pour cela.

En général, l'activité asynchrone n'est pas la même chose que le threading, mais dans iOS, elles sont implémentées de cette façon. Ce n'est pas vrai pour toutes les langues. Nous gérons généralement différentes tâches asynchrones à l'aide de boucles d'exécution.

16
Kunal Balani

Swift 3, 4, 4,2 Synchrone signifie que le thread qui a initié cette opération attendra pour que la tâche se termine avant de continuer.

DispatchQueue.main.sync {

}

Asynchrone signifie que Complète une tâche en arrière-plan et peut vous avertir de l'achèvement de la tâche, ce qui signifie qu'elle n'attendra pas.

DispatchQueue.main.async {

}
4
Akbar Khan

Asynchrone signifie hors ligne, synchrone en ligne. Vous pouvez effectuer des tâches synchrones et bloquer plusieurs threads à la fois.

Si vous êtes dans un thread d'arrière-plan et que vous souhaitez mettre à jour tout un ensemble de l'interface utilisateur, vous appelez le thread principal dans une file d'attente dispatch. Si vous appelez dispatch_sync alors le code dans lequel vous vous trouvez attend que dispatch soit terminé, bloquant ainsi le thread d'arrière-plan dans lequel vous vous trouvez et bloquant l'interface utilisateur pendant la mise à jour du thread principal.

Mais si vous appelez dispatch_async le thread d'arrière-plan continuerait avec le reste du code répertorié et le thread principal exécuterait le bloc dispatch demandé.

La même chose peut être dite quand dans le fil principal. si vous appelez un dispatch_sync du thread principal vers une file d'attente globale ou personnalisée, il bloque le thread principal pendant qu'il exécute le code dans un thread séparé. Je ne peux pas dire que je connais un cas où cela serait utilisé, mais c'est sûrement possible.

Chaque fois que vous avez du code de calcul, un code de service Web, une récupération de code, ce qui n'affecte pas l'interface utilisateur, il est préférable de le faire dans un thread séparé. Pour ce genre de choses je ferais un dispatch_async dans un fil global. Puis, une fois ce code terminé, je lancerais un dispatch_async retournez dans le thread principal pour lui dire de mettre à jour l'interface utilisateur avec tout ce que je viens de calculer.

Synchrone signifie blocage, asynchrone signifie qu'il se terminera ultérieurement (peut-être maintenant) sans bloquer ce que vous êtes en train de faire.

3
Putz1103

Cette discussion y répond à peu près: Asynchrone vs multithreading - Y a-t-il une différence?

Dans le cas général, un appel asynchrone ne crée pas nécessairement un nouveau thread. C'est une façon de l'implémenter, avec un pool de threads ou un processus externe préexistant. Cela dépend fortement du langage, du modèle d'objet (le cas échéant) et de l'environnement d'exécution.

Asynchrone signifie simplement que le thread appelant n'attend pas la réponse et que l'activité asynchrone ne se produit pas dans le thread appelant.

Donc, fondamentalement, d’autres activités peuvent se produire en attendant que quelque chose soit chargé, mais cela peut être fait ou non sur des threads distincts.

2
mjdth