web-dev-qa-db-fra.com

Que signifie main.sync dans global (). Async?

Dans Swift, j'ai parfois utilisé ce type de motif.

DispatchQueue.global().async {
    // do stuff in background, concurrent thread

    DispatchQueue.main.sync {
        // update UI
    }
}

Le but de ce modèle est clair. Effectuez des calculs longs dans le thread global afin que l'interface utilisateur ne soit pas verrouillée et mettez à jour l'interface utilisateur dans le thread principal une fois le calcul terminé.

Et s'il n'y a rien à calculer? Je viens de trouver une logique dans mon projet qui

//A
DispatchQueue.main.sync {
    // do something
}

plante mais

// B
DispatchQueue.global().async {
    DispatchQueue.main.sync {
        // do something
    }
}

ne plante pas.

Comment sont-ils différents? Et la casse B est-elle différente avec cela?

// C
DispatchQueue.main.async {
    // do something
}

Et encore une question. Je sais que le thread principal est la file d'attente série, mais si j'exécute plusieurs blocs de code dans plusieurs main.async, cela fonctionne comme une file d'attente simultanée.

DispatchQueue.main.async {
    // do A
}

DispatchQueue.main.async {
    // do B
}

Si le thread principal est vraiment une file d'attente série, comment peuvent-ils s'exécuter simultanément? Si c'est juste une tranche de temps, comment sont-ils différents avec une file d'attente simultanée globale autre que le thread principal peut mettre à jour l'interface utilisateur?

18
Ryan

x.sync signifie que la file d'attente des appels se mettra en pause et attendra la fin du bloc de synchronisation pour continuer. donc dans votre exemple:

DispatchQueue.global().async {
    // yada yada something
    DispatchQueue.main.sync {
        // update UI
    }
    // this will happen only after 'update UI' has finished executing
}

Habituellement, vous n'avez pas besoin de sync pour revenir à main, async est probablement assez bon et plus sûr pour éviter les blocages. À moins que ce soit un cas spécial où vous devez attendre que quelque chose se termine sur le principal avant de poursuivre votre tâche asynchrone.

Comme pour Un exemple de plantage - appeler la synchronisation et cibler la file d'attente actuelle est un blocage (la file d'attente d'appel attend la fin du bloc de synchronisation, mais elle ne démarre pas car la file d'attente cible (la même) est occupée à attendre l'appel de sync à terminer) et c'est probablement pourquoi le crash.

Quant à la planification de plusieurs blocs sur la file d'attente principale avec async: ils ne seront pas exécutés en parallèle - ils se produiront l'un après l'autre. Ne présumez pas non plus que la file d'attente == thread. La planification de plusieurs blocs sur la même file d'attente peut créer autant de threads que le système le permet. La file d'attente principale est spéciale car elle utilise le thread principal.

22
Mindaugas

Files d'attente [Plus]

GCD propose trois principaux types de files d'attente:

1. File d'attente principale: s'exécute sur le thread principal et est une file d'attente série .
2. Files d'attente globales: files d'attente simultanées partagées par l'ensemble du système. Il existe quatre files d'attente de ce type avec des priorités différentes: élevée, par défaut, faible et en arrière-plan. La file d'attente de priorité en arrière-plan a la priorité la plus faible et est limitée dans toute activité d'E/S pour minimiser l'impact négatif du système.
3. Files d'attente personnalisées: files d'attente que vous créez, qui peuvent être en série ou simultanées. Les demandes dans ces files d'attente aboutissent en fait dans l'une des files d'attente globales.

Synchrone vs asynchrone

Avec GCD, vous pouvez répartir une tâche soit synchronously ou asynchronously.

Une fonction synchronous renvoie le contrôle à l'appelant une fois la tâche terminée. Il bloque la file d'attente et attend que la tâche soit terminée. Vous pouvez planifier une unité de travail de manière synchrone en appelant DispatchQueue.sync(execute:).

Une fonction asynchronous retourne immédiatement, ordonnant le démarrage de la tâche mais sans attendre qu'elle se termine. Ainsi, une fonction asynchrone n'empêche pas le thread d'exécution en cours de passer à la fonction suivante. Vous pouvez planifier une unité de travail de manière asynchrone en appelant DispatchQueue.async(execute:).

Résumé

En général, vous souhaitez utiliser async lorsque vous devez effectuer une tâche réseau ou gourmande en CPU en arrière-plan et ne pas bloquer le thread actuel.

Voici un guide rapide sur comment et quand utiliser les différentes files d'attente avec async:

  • File d'attente principale: Il s'agit d'un choix courant pour mettre à jour l'interface utilisateur après avoir terminé le travail dans une tâche sur une file d'attente simultanée. Pour ce faire, vous codez une fermeture à l'intérieur d'une autre. Cibler la file d'attente principale et appeler async garantit que cette nouvelle tâche s'exécutera quelque temps après la fin de la méthode actuelle.
  • File d'attente globale: Il s'agit d'un choix courant pour effectuer un travail non-interface utilisateur en arrière-plan.
  • File d'attente série personnalisée: Un bon choix lorsque vous souhaitez effectuer un travail d'arrière-plan en série et le suivre. Cela élimine les conflits de ressources et les conditions de concurrence, car vous savez qu'une seule tâche à la fois est en cours d'exécution. Notez que si vous avez besoin des données d'une méthode, vous devez déclarer une autre fermeture pour les récupérer ou envisager d'utiliser sync.

Erreur courante:

Appel DispatchQueue.main.sync de la file d'attente main en conséquence, l'application sera gelée car la file d'attente appelante (main) attendra la fin du bloc distribué, mais elle (bloc distribué) ne sera même pas capable de démarrer (car la file d'attente main a été arrêtée et en attente)

Général asynchrone vs synchrone

La source est ici

2
yoAlex5