web-dev-qa-db-fra.com

iOS GCD: Différence entre une file d'attente globale et celle avec une priorité en arrière-plan (DISPATCH_QUEUE_PRIORITY_BACKGROUND)?

Je lis Guide de programmation d'accès concurrentiel et les choses me confondent.

Je vois beaucoup de code invoquer ce qui suit pour toute tâche en arrière-plan:

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Maintenant, ce que je veux dire par "arrière-plan" est le sens populaire:

Quelque chose qui est exécuté ailleurs que sur le thread principal (UI)

Ainsi, à la suite des documents, l'instruction ci-dessus renvoie toute file d'attente non-thread principal avec des priorités différentes.

Ma question est - pourquoi alors DISPATCH_QUEUE_PRIORITY_BACKGROUND existe? Dernièrement, je vois également de nombreuses tâches asynchrones utilisant DISPATCH_QUEUE_PRIORITY_BACKGROUND spécifiquement pour effectuer des tâches en arrière-plan.

Les files d'attente ne sont pas renvoyées avec DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_PRIORITY_LOW ou DISPATCH_QUEUE_PRIORITY_HIGH s'éloigne beaucoup du thread principal, s'ils sont retournés en utilisant dispatch_get_global_queue?

Ne sont-ils pas des files d'attente en arrière-plan? À quoi sert une file d'attente renvoyée avec DISPATCH_QUEUE_PRIORITY_BACKGROUND servir? J'ai déjà fait référence à cela mais cela ne clarifie pas grand-chose, à part le sens populaire que j'ai mentionné ci-dessus.

Je suis sûr que je suis assez confus avec les mots - arrière-plan et files d'attente. Si quelqu'un peut expliquer (mieux, graphiquement) - sera d'une grande aide.

35
Nirav Bhatt

Si vous avez de nombreuses tâches d'arrière-plan, le ou les CPU de votre appareil seront partagés entre tous. La plupart du temps, c'est la bonne chose à faire. Si une tâche prend trop de temps à terminer, vous résolvez le problème en essayant de la rendre plus efficace.

Dans de très rares cas, vous pouvez avoir une tâche qui prend beaucoup de temps, mais c'est Ok pour l'attendre. Vous lui donnez donc la priorité HISTORIQUE. S'il y a du travail à faire chez NORMAL prioritaire, ce travail sera effectué en premier, et uniquement lorsqu'il y a un CPU de rechange qui ne fait rien d'autre, la tâche BACKGROUND sera effectuée. Et il y a la file d'attente avec une priorité ÉLEVÉE; les tâches de cette file d'attente seront exécutées en premier; vous feriez cela si une tâche spécifique doit être terminée aussi rapidement que possible même si cela signifie que d'autres tâches sont retardées.

Du point de vue de votre logique de programmation, les trois files d'attente sont identiques. Cela affecte simplement les tâches que le système d'exploitation essaie de terminer en premier et celles auxquelles il ne se soucie pas beaucoup.

14
gnasher729

Ceci est expliqué assez bien dans l'en-tête dispatch/queue.h:

DISPATCH_QUEUE_PRIORITY_HIGH Les éléments envoyés à la file d'attente s'exécuteront à haute priorité, c'est-à-dire que la file d'attente sera planifiée pour exécution avant toute priorité par défaut ou file d'attente à faible priorité.

DISPATCH_QUEUE_PRIORITY_DEFAULT Les éléments envoyés à la file d'attente s'exécuteront avec la priorité par défaut, c'est-à-dire que la file d'attente sera planifiée pour exécution après que toutes les files d'attente à priorité élevée ont été planifiées, mais avant que toutes les files d'attente à priorité faible aient été planifiées.

DISPATCH_QUEUE_PRIORITY_LOW Les éléments envoyés à la file d'attente s'exécuteront à faible priorité, c'est-à-dire que la file d'attente sera planifiée pour être exécutée une fois que toutes les files d'attente de priorité et de priorité élevée auront été planifiées.

DISPATCH_QUEUE_PRIORITY_BACKGROUND Les éléments envoyés à la file d'attente s'exécuteront en priorité en arrière-plan, c'est-à-dire que la file d'attente sera planifiée pour être exécutée une fois que toutes les files d'attente de priorité supérieure auront été planifiées et que le système exécutera les éléments de cette file d'attente sur un thread avec un état en arrière-plan selon setpriority (2) ( c'est-à-dire que les E/S disque sont limitées et que la priorité de planification du thread est définie sur la valeur la plus basse).

Et gardez à l'esprit qu'il s'agit d'une file d'attente globale . D'autres choses, comme les cadres du système, peuvent y être programmées. Il est très facile d'affamer les bandes prioritaires - s'il y a beaucoup de DISPATCH_QUEUE_PRIORITY_HIGH les tâches étant planifiées, les tâches ayant la priorité par défaut peuvent devoir attendre un certain temps avant de s'exécuter. Et les tâches dans DISPATCH_QUEUE_PRIORITY_BACKGROUND peuvent devoir attendre très longtemps , car toutes les autres priorités au-dessus doivent être vides.

De nombreux développeurs abusent de la file d'attente simultanée globale. Ils veulent exécuter un bloc, ont besoin d'une file d'attente et l'utilisent simplement à la priorité par défaut. Ce type de pratique peut entraîner des bogues très difficiles à résoudre. La file d'attente simultanée globale est une ressource partagée et doit être traitée avec soin. Dans la plupart des cas, il est plus logique de créer une file d'attente privée.

Une file d'attente simultanée n'est pas asynchrone, elle est simultanée. Des tâches synchrones peuvent toujours y être planifiées et elles s'exécuteront toujours de manière synchrone. Les files d'attente simultanées, comme les files d'attente série, sont retirées de la file d'attente dans l'ordre FIFO. Elles exécutent des blocs simultanément, contrairement aux files d'attente série. Simultanément et asynchrone ne sont pas la même chose.

Gardez également à l'esprit que si le thread principal est inactif, une file d'attente simultanée peut réutiliser ce thread - et préférera en fait le faire à la création de nouveaux threads. L'utilisation d'une file d'attente simultanée ne garantit pas que vous ne bloquerez pas l'interface utilisateur:

Les blocs soumis à ces files d'attente de répartition sont invoqués sur un pool de threads entièrement géré par le système. Aucune garantie n'est donnée concernant le thread sur lequel un bloc sera invoqué; cependant, il est garanti qu'un seul bloc soumis à la file d'attente de répartition FIFO sera invoqué à la fois.

GCD ne donne aucune garantie sur le thread qui sera utilisé pour exécuter un bloc sur une file d'attente simultanée. Si vous utilisez la file d'attente principale, le bloc sera exécuté en série sur le thread principal. Une file d'attente simultanée peut utiliser n'importe quel thread et, en tant qu'optimisation, préférera utiliser des threads existants. Il ne créera un nouveau thread que si aucun thread n'est disponible pour être réutilisé. Et en fait le fil principal est souvent son premier choix (si le fil principal est disponible pour le travail) car il est "chaud".

Pour réitérer: Avec Grand Central Dispatch, vous pouvez être certain qu'une tâche s'exécutera sur le thread principal (en se soumettant à la file d'attente principale). Vous ne pouvez pas être certain qu'une tâche ne s'exécutera pas sur le thread principal.

37
quellish