La syntaxe et la sémantique sont déjà bien définies par d'autres excellentes réponses à cette question. Parce que l' exécution et les performances ne sont pas bien détaillées, j'ajouterai ma réponse.
Quelle est la différence fonctionnelle entre ces 3?
J'avais toujours considéré l'atomique comme un défaut assez curieux. Au niveau de l'abstraction où nous travaillons, l'utilisation des propriétés atomiques pour une classe comme véhicule pour atteindre une sécurité de filetage à 100% est un cas d'angle. Pour des programmes multithreads vraiment corrects, l'intervention du programmeur est presque certainement une exigence. Pendant ce temps, les caractéristiques de performance et l'exécution n'ont pas encore été détaillées en détail. Après avoir écrit des programmes lourdement multithread au fil des ans, j'avais déclaré mes propriétés comme nonatomic
tout le temps parce que l'atomique n'était pas sensé à quelque fin que ce soit. Au cours de la discussion des détails des propriétés atomiques et non anatomiques de cette question , j'ai fait du profilage rencontré quelques résultats curieux.
Exécution
D'accord. La première chose que je voudrais clarifier est que l'implémentation de verrouillage est définie par l'implémentation et abstraite. Louis utilise @synchronized(self)
dans son exemple - j'ai vu cela comme une source commune de confusion. La mise en œuvre ne fait utiliser @synchronized(self)
; il utilise des verrous rotatifs au niveau de l'objet . L'illustration de Louis est bonne pour une illustration de haut niveau utilisant des constructions que nous connaissons tous, mais il est important de savoir qu'elle n'utilise pas @synchronized(self)
.
Une autre différence est que les propriétés atomiques conserveront / relâcheront le cycle de vos objets dans le getter.
Performance
Voici la partie intéressante: les performances utilisant des accès à la propriété atomique dans des cas non contestés (par exemple, un seul thread) peuvent être très rapides dans certains cas. Dans des cas moins qu'idéaux, l'utilisation des accès atomiques peut coûter plus de 20 fois les frais généraux de nonatomic
. Alors que le cas contesté utilisant 7 threads était 44 fois plus lent pour la structure à trois octets (2,2 GHz Core i7 Quad Core, x86_64). La structure à trois octets est un exemple de propriété très lente.
Note intéressante: les accesseurs définis par l'utilisateur de la structure à trois octets étaient 52 fois plus rapides que les accesseurs atomiques synthétisés; ou 84% de la vitesse des accessoires non anatomiques synthétisés.
Les objets dans les cas contestés peuvent également dépasser 50 fois.
En raison du nombre d'optimisations et de variations dans les implémentations, il est assez difficile de mesurer les impacts réels dans ces contextes. Vous pouvez souvent entendre quelque chose comme "Faites-lui confiance, à moins que vous ne vous fassiez un profil et que vous ne trouviez que c'est un problème". En raison du niveau d'abstraction, il est en fait assez difficile de mesurer l'impact réel. Glaner les coûts réels des profils peut prendre beaucoup de temps et, en raison des abstractions, être tout à fait inexact. De plus, ARC vs MRC peut faire une grande différence.
Revenons donc en arrière, ne nous concentrant pas sur la mise en œuvre des accès à la propriété, nous inclurons les suspects habituels comme objc_msgSend
, et examinons certains résultats de haut niveau du monde réel pour de nombreux appels à un NSString
getter dans des cas non contestés (valeurs en secondes):
- MRC | non anatomique | getters implémentés manuellement: 2
- MRC | non anatomique | getter synthétisé: 7
- MRC | atomique | getter synthétisé: 47
- ARC | non anatomique | getter synthétisé: 38 (note: l'ARC ajoute le nombre de références en cyclant ici)
- ARC | atomique | getter synthétisé: 47
Comme vous l'avez probablement deviné, l'activité / le cycle de comptage de référence est un contributeur important avec l'atomique et sous l'ARC. Vous verriez également de plus grandes différences dans les cas contestés.
Bien que je porte une attention particulière à la performance, je dis toujours la sémantique d'abord! . Pendant ce temps, la performance est une faible priorité pour de nombreux projets. Cependant, connaître les détails d'exécution et les coûts des technologies que vous utilisez ne fait certainement pas de mal. Vous devez utiliser la bonne technologie pour vos besoins, objectifs et capacités. J'espère que cela vous fera économiser quelques heures de comparaisons et vous aidera à prendre une décision plus éclairée lors de la conception de vos programmes.