1. John Siracusa
    1. Mountain Lion
      1. Introduction
      2. Achat et installation
      3. Changements d'interface (1)
      4. Changements d'interface (2)
      5. Changements d'interface (3)
      6. Applications (1)
      7. Applications (2)
      8. Applications (3)
      9. Applications (4)
      10. Applications (5)
      11. iCloud(1)
      12. iCloud(2)
      13. iCloud(3)
      14. Gatekeeper(1)
      15. Gatekeeper(2)
      16. Retina et HiDPI
      17. Fourre-tout (1)
      18. Fourre-tout (2)
      19. Fourre-tout (3)
      20. Fourre-tout (4)
      21. Fourre-tout (5)
      22. Fourre-tout (6)
      23. Recommandations
      24. Deux pères, un fils
    2. Lion
      1. Introduction
      2. Installation
      3. Revoir les fondamentaux
      4. Redimensionnement des fenêtres
      5. Et voici pour les cinglés
      6. La gestion des fenêtres
      7. Le modèle de document
      8. le modèle des processus
      9. Les éléments internes (1)
      10. Les éléments internes (2)
      11. ARC
      12. Le système de fichiers
      13. Ses modifications dans Lion
      14. Documents, résolution
      15. Le Finder
      16. Mail, Safari
      17. Fourre tout (1)
      18. Fourre tout (2)
      19. Recommendations
    3. Snow Leopard
      1. Introduction
      2. Le ticket d'entrée
      3. L'installation
      4. Nouvel aspect
      5. Détails internes
      6. Quick Time X
      7. Système de fichiers
      8. Faire plus avec plus
      9. LLVM et Clang
      10. Les blocs
      11. Concurrence
      12. Grand Central Dispatch
      13. Asynchronicité
      14. Open CL
      15. La différence...
      16. Quick Time Player
      17. Le Dock
      18. Le Finder
      19. Exchange
      20. Performances
      21. Fourre tout (1)
      22. Fourre tout (2)
      23. Le futur
    4. Leopard
      1. Introduction
      2. L'héritage
      3. Nouvel aspect 1
      4. Nouvel aspect 2
      5. Le noyau
      6. 64 bits
      7. FS Events
      8. Core animation
      9. Quartz GL
      10. Core UI
      11. Détails internes
      12. Le Finder
      13. Le Dock
      14. Time Machine
      15. Performances
      16. Pot pourri
      17. Demain
    5. Tiger
      1. Introduction
      2. Retour sur le passé
      3. Nouvel aspect de Tiger
      4. Mises à jour du noyau
      5. Le lancement
      6. Les méta-données
      7. Attributs étendus
      8. Listes de contrôle d'accès
      9. Spotlight 1
      10. Spotlight 2 : analyse et potentiel
      11. Types de fichiers
      12. Méta-données : la fin
      13. Quartz
      14. Quartz 2D Extreme
      15. Core Image
      16. La vidéo sous Tiger
      17. Dashboard
      18. Le Finder
      19. Les performances
      20. Pot pourri
      21. Conclusion
    6. Panther
      1. Introduction
      2. Les précédents
      3. L'installation
      4. Nouvel aspect
      5. Performances
      6. Changement rapide d'utilisateur
      7. Gestion des fenêtres
      8. Exposé
      9. Le Finder
      10. Performance du Finder
      11. Toujours le même
      12. Safari
      13. XCode
      14. Conclusion
    7. Jaguar
      1. Introduction
      2. Le nom
      3. L'installation
      4. Modifications d'Unix
      5. Dévelopeurs...
      6. Quoi de neuf
      7. Rendezvous
      8. Quartz Extrême
      9. Performance
      10. Compositions
      11. Le Finder
      12. Applications
      13. Sherlock
      14. Le portrait
    8. Puma
      1. Prelude
      2. Introduction
      3. Installation
      4. Réglages système
      5. Performance
      6. Redimensionnement des fenêtres
      7. Utilisation de la mémoire
      8. Diagnostics de mémoire
      9. L'environnement Classique
      10. L'interface Utilisateur
      11. Le Finder
      12. Extensions de fichiers
      13. Divers, conclusion
    9. Cheeta (Mac OS X 10.0)
      1. Qu'est ce que Mac OS X
      2. Installation
      3. Le démarrage
      4. Utilisation de la RAM
      5. Performance
      6. Performance des applications
      7. Stabilité
      8. L'interface utilisateur
      9. Le Finder
      10. Le navigateur du Finder
      11. Le Finder (divers)
      12. L'interface utilisateur
      13. Os X Classique
      14. Système de fichiers
      15. Unix
      16. Applications
      17. Conclusion
    10. Les débuts de MacOsX
      1. 1999 : OSX DP2
      2. 2000 : Quartz et Aqua/a>
      3. Fin de la lune de miel
      4. la première bêta publique
      5. 2001 : Mac OS X 10.0
      6. Un investissement
    11. Finder Spatial
      1. Introduction
      2. Interfaces spatiales
      3. Le Finder spatial
      4. Le concierge
      5. Un nouveau Finder
      6. Le browser
      7. Le browser spatial
      8. Finder et méta-données
      9. Les modèles
      10. Pensées finales

L'asynchronicité




D'accord, GCD est une manière élégante d'utiliser avec efficacité le matériel disponible. Mais, est-ce que c'est vraiment mieux que l'approche par le multi-threading utilisée par Be OS ? Nous avons déjà vu quelques façons dont GCD évite les pièges de Be OS (notamment la réutilisation des threads et la gestion d'un paquet global de threads de taille adaptée au matériel utilisé). Mais que dire de la surcharge subie par le programmeur associée à l'utilisation de threads à des endroits où ils compliquent, plutôt qu'ils améliorent l'application ?

GCD représente une philosophie qui est à l'opposé du concept de multi-thread ubiquitaire de Be OS. Plutôt que d'obtenir la réactivité en permettant à chaque composant possible d'une application de s'éxecuter en simultanéité dans son propre thread (et en payant le prix fort en terme de complexité pour le partage des données et les opérations de verrouillage), GCD encourage une approche beaucoup plus limitée et hiérarchique : un thread d'application principale, où tous les évènements utilisateurs sont gérés, et l'interface mise à jour, et des threads spécifiques au programme, qui font le travail voulu.

Autrement dit, GCD n'exige pas des développeurs qu'ils imaginent la meilleure façon de scinder le travail de leur application en une multitudes de threads concurrents (bien que, s'ils sont prêts à le faire, GCD va collaborer et être capable d'aider). A son niveau le plus élémentaire, GCD ambitionne à encourager les développeurs à ne plus penser de façon synchrone, mais asynchrone. Quelque chose du genre : "écrivez votre application comme vous en avez l'habitude, mais s'il y a une partie quelconque du travail dont on peut raisonnablement penser qu'il prendra plus de quelques secondes, alors, pour l'amour de Zarzycki, sortez le du thread principal !"

C'est comme ça ; pas plus, pas moins. Le bannissement de la roulette multicolore est la pierre angulaire de la réactivité de l'interface utilisateur. D'une certaine façon, tout le reste, c'est de la sauce. Mais la plupart des développeurs le savent intuitivement, alors, pourquoi voyons-nous encore cette roulette dans les applications Mac OS X ? Pourquoi toutes les applications n'exécutent-t-elles pas déjà les tâches susceptibles d'être longues dans des threads en tâche de fond ?

Quelques raisons ont déjà été mentionnées (c'est à dire la difficulté de connaître le nombre de threads à créer) mais la raison principale est beaucoup plus réaliste. Isoler un thread, et récupérer son résultat a toujours été un peu difficile. Ce n'est pas tant que c'est techniquement difficile, c'est seulement que cela constitue une rupture, le passage de l'écriture du travail fait par l'application au codage détaillé de la gestion des tâches. Si bien que, notamment dans les cas limites, comme une opération qui peut prendre 3 à 5 secondes, les développeurs la réalisent de façon synchrone, et passent à la suite.

Malheureusement, il y a un nombre surprenant de choses très communes qu'une application peut faire pour s'exécuter rapidement la plupart du temps, mais qui peuvent aussi durer beaucoup plus longtemps que quelques secondes quand quelque chose va mal. Tout ce qui concerne le système de fichiers peut caler aux niveaux les plus bas de l'OS (c'est à dire avec des appels read() et write() qui se bloquent), et être sujet à une suspension de très longue durée non prise en compte par le développeur de l'application. La même chose intervient pour les recherches de noms (par exemple DNS ou LDAP), qui presque toujours s'exécutent instantanément, mais laissent beaucoup d'applications pratiquement sans défense quand elles décident de prendre tout leur temps pour renvoyer un résultat. Si bien que les applications les plus méticuleusement construites peuvent finir par vous renvoyer la roulette multicolore en pleine figure de temps en temps.

Avec GCD, Apple dit que cela n'a pas à se produire. Par exemple, supposez qu'une application basée sur un document a un bouton qui, quand on clique dessus, analyse le document en question, et affiche des statistiques intéressantes à son propos. Dans les cas courants, cette analyse doit se faire en moins d'une seconde, si bien qu'on utilise le code suivant pour associer le bouton à l'action :

listing

La première ligne du corps de la fonction analyse le document, la seconde met à jour l'état interne de l'application, et la troisième dit à l'application que la vue statistiques doit être mise à jour pour être conforme au nouvel état. Tout cela suit un patron très courant, et ça marche bien aussi longtemps qu'aucune de ces étapes, qui tournent toutes dans le même thread principal, ne prend pas trop longtemps. Parce que, après que l'utilisateur a pressé le bouton, l'application a besoin de prendre en compte cette entrée aussi vite que possible, pour revenir à la boucle d'évènements principale, et gérer l'action suivante de l'utilisateur.

Le code en question marche bien jusqu'à ce que l'utilisateur ouvre un document très gros, ou très complexe. Soudain, l'étape d'analyse ne prend plus une ou deux secondes mais 15 ou 30. Salut, la roulette multicolore. Et alors, le developpeur risque de tergiverser : "c'est vraiment une situation exceptionnelle. La plupart de mes utilisateurs n'ouvriront jamais un fichier aussi gros. Et de toute façon, je n'ai pas l'intention de commencer à lire la documentation, et à rajouter du code supplémentaire à cette fonction simple de quatre lignes. Ce rajout amoindrirait le code qui fait du bon travail".

Bien, et si je vous disais que vous pouvez déplacer l'analyse du document à l'arrière plan en ajoutant seulement 2 lignes de code, (oui, et aussi 2 lignes d'accolades de fermeture), toutes incluses dans la fonction existante ? Pas d'objets globaux, pas de gestion des threads, pas de fonction de rappel, pas d'arrangement des arguments, pas d'objets contextuels, pas même de variables additionnelles. Admirez ! C'est Grand Central Dispatch.

listing
Il y a une foutue accumulation de puissance dans ces deux lignes de code. Toutes les fonctions de GCD commencent par dispatch_, et vous pouvez voir quatre appels de ce type dans les lignes en bleu du code ci-dessus. La clé à l'intrusion minimale de ce code est révélées dans le second argument des deux appels à dispatch_async(). Jusqu'à présent, j'ai abordé les "unités de travail" sans préciser exactement comment GCD les organise. La réponse est là, et devrait sembler évidente avec du recul : les blocs ! La capacité des blocs à s'accaparer le contexte environnant est ce qui permet à ces appels GCD d'être lâchés en plein dans du code existant, sans avoir besoin de dispositions supplémentaires, ni d'une réorganisation, ni d'autres contorsions au service de l'API.

Mais la meilleure partie de ce code est la façon dont il détecte quand la tâche en arrière plan a terminé, pour montrer le résultat. Dans le code synchrone, l'appel à la méthode analyse, et le code pour mettre à jour l'affichage de l'application figurent simplement dans l'ordre voulu à l'intérieur de la fonction. Dans le mode asynchrone, miraculeusement, c'est aussi le cas. Voilà comment ça marche.

L'appel externe à dispatch_async() dépose une tâche sur la queue globale simultanée. Cette tâche, représentée par le bloc passé comme second argument, contient l'appel à la méthode analyse potentiellement consommatrice de temps, plus un autre appel à dispatch_async qui met la tâche sur la queue principale -une queue sérielle qui exécute le thread principal- pour mettre à jour l'interface utilisateur de l'application.

Les mises à jour de l'interface utilisateur doivent toutes être faites dans le thread principal pour une application Cocoa, si bien que le code dans le bloc intérieur ne pourrait pas être exécuté ailleurs. Mais plutôt que d'obliger le thread en arrière plan à renvoyer une forme spécifique de notification au thread principal quand l'appel à la méthode analyse est terminé (donc à ajouter du code à l'application pour détecter et gérer cette notification), le travail qui doit être accompli sur le thread principal pour mettre à jour l'affichage est encapsulé dans un autre bloc à l'intérieur du bloc le plus gros. Quand l'appel à analyse est terminé, le bloc interne est déposé dans la queue principale, où il va (le cas échéant) s'exécuter dans le thread principal, et faire son travail consistant à mettre à jour l'affichage.

Simple, élégant, et efficace. Et pour les développeurs, plus d'excuses...

Croyez-le ou non, c'est tout aussi simple de prendre une implémentation sérielle de tout un ensemble d'opérations indépendantes, et de les parallèliser. Le code ci-dessous fonctionne sur count éléments de data, et récapitule les résultats quand tous les éléments ont été pris en compte.

listing
Et voici maintenant la version parallèle qui dépose une tâche séparée sur la queue globale simultanée. (Encore une fois, c'est à GCD de décider combien de threads il va effectivement utiliser pour exécuter ces tâches).

listing

Et là, vous l'avez : une boucle for remplacée par un équivalent de calcul simultané dans une ligne de code. Aucune préparation, pas de variables additionnelles, pas de décisions impossibles à prendre à propos du nombre optimal de threads, pas de travail supplémentaire requis pour attendre que tous ces tests indépendants soient terminés. (L'appel à dispatch_apply() ne va pas se terminer avant que toutes les tâches qu'il a distribuées ne se soient finies). Ahurissant.

L'excellence de Grand central

De toutes les APIs rajoutées à Léopard des neiges, Grand Central Dispatch a les implications les plus profondes sur le futur de Mac OS X. Jamais auparavant, il n'avait été aussi facile de travailler de façon asynchrone, et de répartir la charge de travail entre de nombruex CPUs.

Quand j'ai entendu parler de Grand central Dispatch pour la première fois, j'étais très sceptique. Les cerveaux les plus éminents de l'informatique ont travaillé pendant des décennies sur le problème de la meilleure façon de parallèliser les charges de calcul. Et maintenant, Apple promettait apparemment de résoudre ce problème ? Ridicule !

Mais Grand Central Dispatch ne résout pas ce problème du tout. Il ne fournit aucune aide dans la façon de décider comment partager votre travail en tâches indépendamment exécutables, autrement dit choisir quels morceaux peuvent être exécutés de façon asynchrone ou parallèle. C'est encore entièrement le rôle du développeur (et c'est encore très difficile). Ce qu'apporte GCD à la place, est beaucoup plus pragmatique. Quand un développeur a identifié quelque chose qui peut être séparé en tâches simultanées, GCD rend la chose aussi facile et non intrusive que possible pour le réaliser effectivement.

L'utilisation des queues FIFO, et particulièrement l'existence des queues sérialisées , semblent aller à l'encontre de l'esprit d'une simultanéité ubiquitaire. Mais nous avons vu où l'idéal platonique du multithread conduit, et ce n'est pas un endroit plaisant pour les développeurs.

L'un des slogans utilisés par Apple pour Grand Central Dispatch est "des îles de sérialisation dans un océan de simultanéité". Cela correspond bien à la réalité pratique qui consiste à rajouter plus de simultanéité aux applications de bureau qui tournent actuellement. Ces îles sont ce qui protège les développeurs des problème épineux de l'accès simultané aux données, du verrouillage, et autres pièges du multi-threading. Les développeurs sont encouragés à identifier les fonctions de leurs applications qui seront mieux exécutées à l'écart du thread principal, même si elles consistent en plusieurs tâches séquentielles, ou en tâches indépendantes. GCD facilite la partition d'une unité de travail tout en maintenant l'ordre existant et les dépendances entre les sous-tâches.

Ceux qui ont une certaine expérience dans la programmation multithread peuvent ne pas être impressionnés par GCD. Ainsi, Apple a fait un paquet de threads. Quel défi ! Ça a toujours été le cas. Mais les anges sont dans les détails. Oui, l'implémentation des queues et des threads a une élégante simplicité, et l'incorporer dans les couches les plus basses de l'OS contribue à abaisser la hauteur de la barrière d'entrée, mais c'est l'API construite autour des blocs qui rend Grand Central Dispatch aussi attractif pour les développeurs. Tout comme Time Machine fut le "premier dispositif de sauvegarde que les gens utilisent réellement", Grand Central Dispatch est prêt à répandre la conception asynchrone des applications, jusqu'à présent un art obscur, auprès de tous les développeurs de Mac OS X. Je ne peux pas attendre.