web-dev-qa-db-fra.com

Comment Swift peut-il être tellement plus rapide que Objective-C dans ces comparaisons?

Apple a lancé son nouveau langage de programmation Swift à WWDC14 . Dans la présentation, ils ont fait des comparaisons de performances entre Objective-C et Python. Ce qui suit est une image de l'une de leurs diapositives, d'une comparaison de ces trois langues effectuant un tri d'objet complexe:

enter image description here

Il y avait un graphique encore plus incroyable sur une comparaison des performances utilisant l'algorithme de cryptage RC4 .

Évidemment, il s'agit d'un discours marketing, et ils ne sont pas entrés dans les détails sur la façon dont cela a été mis en œuvre dans chacun. Je me demande cependant:

  1. Comment un nouveau langage de programmation peut-il être tellement plus rapide?
  2. Les résultats d'Objective-C sont-ils causés par un mauvais compilateur ou y a-t-il quelque chose de moins efficace dans Objective-C que Swift?
  3. Comment expliqueriez-vous une augmentation de 40% des performances? Je comprends que la collecte des ordures/le contrôle de référence automatisé peut produire des frais supplémentaires, mais autant?
117
Yellow

Premièrement, (IMO) comparer avec Python n'a presque aucun sens. Seule la comparaison avec Objective-C est significative.

  • Comment un nouveau langage de programmation peut-il être tellement plus rapide?

Objective-C est un langage lent. (Seule la partie C est rapide, mais c'est parce que c'est C) Elle n'a jamais été extrêmement rapide. C'était juste assez rapide pour leur objectif (d'Apple), et plus rapide que leurs anciennes versions. Et c'était lent parce que ...

  • L'Objective-C résulte-t-il d'un mauvais compilateur ou y a-t-il quelque chose de moins efficace dans Objective-C que Swift?

Objective-C garantit que chaque méthode sera distribuée dynamiquement. Aucune expédition statique du tout. Cela n'a pas permis d'optimiser davantage un programme Objective-C. Eh bien, peut-être que la technologie JIT peut être utile, mais AFAIK, Apple déteste vraiment les caractéristiques de performance imprévisibles et la durée de vie de l'objet. Je ne pense pas qu'ils aient adopté des trucs JIT. Swift n'a pas une telle garantie de répartition dynamique à moins que vous ne mettiez un attribut spécial pour la compatibilité Objective-C.

  • Comment expliqueriez-vous une augmentation de 40% des performances? Je comprends que la collecte des ordures/le contrôle de référence automatisé peut produire des frais supplémentaires, mais autant?

GC ou RC n'a pas d'importance ici. Swift utilise également RC principalement. Aucun GC n'est là, et ne le fera pas à moins qu'il y ait un énorme saut architectural sur la technologie GC. (IMO, c'est pour toujours) je crois Swift a beaucoup plus de place pour l'optimisation statique. Surtout des algorithmes de chiffrement de bas niveau, car ils s'appuient généralement sur d'énormes calculs numériques, et c'est une énorme victoire pour les langues à répartition statique.

En fait, j'ai été surpris car 40% semble trop petit. Je m'attendais à bien plus. Quoi qu'il en soit, il s'agit de la version initiale, et je pense que l'optimisation n'était pas la principale préoccupation. Swift n'est même pas complet! Ils amélioreront les choses.

Mise à jour

Certains continuent de m'embêter pour affirmer que la technologie GC est supérieure. Bien que les choses ci-dessous puissent être discutables, et juste mon opinion très biaisée, mais je pense que je dois dire pour éviter cet argument inutile.

Je sais ce que sont les GC conservateurs/traçants/générationnels/incrémentiels/parallèles/en temps réel et comment ils sont différents. Je pense que la plupart des lecteurs le savent déjà. Je suis également d'accord pour dire que GC est très agréable dans certains domaines, et montre également un débit élevé dans certains cas.

Quoi qu'il en soit, je soupçonne que la revendication de débit GC est toujours meilleure que RC. La plupart des frais généraux de RC proviennent de l'opération de comptage des références et du verrouillage pour protéger la variable du nombre de références. Et l'implémentation RC fournit généralement un moyen d'éviter les opérations de comptage. Dans Objective-C, il y a __unsafe_unretained et dans Swift, (bien que ce ne soit toujours pas clair pour moi) unowned stuff. Si le coût de l'opération de comptage des références n'est pas acceptable, vous pouvez essayer de les désactiver de manière sélective en utilisant la mécanique. Théoriquement, nous pouvons simuler un scénario de propriété presque unique en utilisant des références non conservées de manière très agressive pour éviter les frais généraux de RC. Je pense également que le compilateur peut éliminer automatiquement certaines opérations RC inutiles évidentes.

Contrairement au système RC, AFAIK, l'opt-out partiel de types de référence n'est pas une option sur le système GC.

Je sais qu'il existe de nombreux graphiques et jeux publiés qui utilisent un système basé sur GC, et je sais également que la plupart d'entre eux souffrent d'un manque de déterminisme. Non seulement pour les caractéristiques de performance, mais également pour la gestion de la durée de vie des objets. Unity est principalement écrit en C++, mais la minuscule partie C # provoque tous les problèmes de performances étranges. Applications hybrides HTML et souffrant toujours de pics imprévisibles sur n'importe quel système. Largement utilisé ne signifie pas que c'est supérieur. Cela signifie simplement que c'est facile et populaire pour les personnes qui n'ont pas beaucoup d'options.

Mise à jour 2

Encore une fois pour éviter des discussions ou des débats inutiles, j'ajoute quelques détails supplémentaires.

@Asik a fourni une opinion intéressante sur les pointes du GC. C'est que nous pouvons considérer l'approche value-type-partout comme un moyen de désactiver les éléments GC. C'est assez attractif, et même réalisable sur certains systèmes (approche purement fonctionnelle par exemple). Je suis d'accord que c'est Nice en théorie. Mais en pratique, cela pose plusieurs problèmes. Le plus gros problème est que l'application partielle de cette astuce ne fournit pas de véritables caractéristiques sans pic.

Parce que le problème de latence est toujours tout ou rien problème. Si vous avez un pic de trame pendant 10 secondes (= 600 images), alors tout le système échoue évidemment. Il ne s'agit pas de savoir comment mieux ou pire. C'est juste passer ou échouer. (ou moins de 0,0001%) Alors, où est la source du pic de GC? C'est une mauvaise répartition de la charge GC. Et c'est parce que le GC est fondamentalement indéterministe. Si vous faites des ordures, cela activera le GC et un pic se produira éventuellement. Bien sûr, dans le monde idéal où la charge GC sera toujours idéale, cela ne se produira pas, mais je vis dans un monde réel plutôt que dans un monde idéal imaginaire.

Ensuite, si vous voulez éviter les pics, vous devez supprimer tous les types de référence de tout le système. Mais c'est difficile, fou, et même impossible en raison d'une partie inamovible telle que le système et la bibliothèque de base .NET. L'utilisation d'un système non GC est beaucoup plus facile.

Contrairement à GC, RC est fondamentalement déterministe, et vous n'avez pas à utiliser cette optimisation folle (uniquement de type valeur uniquement) juste pour éviter un pic. Ce que vous devez faire est de rechercher et d'optimiser la pièce à l'origine du pic. Dans les systèmes RC, la pointe est un problème d'algorithme local, mais dans les systèmes GC, les pointes sont toujours un problème système global.

Je pense que ma réponse est trop hors sujet, et surtout juste une répétition des discussions existantes. Si vous voulez vraiment revendiquer une supériorité/infériorité/alternative ou autre chose de GC/RC, il y a beaucoup de discussions sur ce site et StackOverflow, et vous pouvez continuer à vous battre là-bas.

62
Eonil

Étant 3,9 fois plus rapide que python, le langage qui perd systématiquement la plupart des benchmarks par une marge considérable (ok, c'est à égalité avec Perl, Ruby et PHP; mais il perd à tout ce qui est typé statiquement), n'est rien on devrait se vanter.

Le jeu de benchmarks montre les programmes C++ qui sont plus d'un ordre de grandeur plus rapides que les programmes python dans la plupart des cas. Ce n'est pas beaucoup mieux en comparaison avec Java, C # (sur Mono), OCaml, Haskell et même Clojure, qui n'est pas typé statiquement.

La vraie question est donc de savoir comment Objective-C n'est que 2,8 fois plus rapide que python. Apparemment, ils ont soigneusement choisi une référence où l'envoi lent et entièrement dynamique d'ObjC fait très mal. Toute langue typée statiquement devrait pouvoir faire mieux. Dans le tri d'objets complexes, il existe de nombreux appels de méthode pour comparer les objets et la comparaison réelle n'était probablement pas très complexe elle-même. Donc, si Swift tire au moins parti des informations de type, il peut facilement faire mieux sur les appels de méthode et il n'y a pas assez d'autres opérations dans lesquelles ObjC pourrait être meilleur.

Bien sûr, comme le jeu de benchmarks le montre clairement, les performances relatives sur différentes tâches varient énormément, donc un benchmark n'est pas vraiment représentatif. S'ils avaient un point de référence là où il avait un plus grand avantage, ils nous auraient montré celui-là à la place, donc pour d'autres tâches, ce n'est probablement pas mieux ou moins.

72
Jan Hudec

Objective-C distribue dynamiquement chaque appel de méthode.

Hypothèse: Le benchmark utilise un typage statique pour laisser le compilateur Swift hisser la recherche de méthode compare hors de la boucle sort. nécessite une restriction de type étroite qui autorise uniquement les objets complexes dans le tableau, pas les sous-classes de complexes.

(Dans Objective-C, vous pouvez hisser la recherche de méthode manuellement si vous le souhaitez vraiment, en appelant le support d'exécution du langage pour rechercher le pointeur de méthode. Vous feriez mieux de vous assurer que toutes les instances du tableau sont de la même classe .)

Hypothèse: Swift optimise les appels de comptage de références hors de la boucle.

Hypothèse: Le benchmark Swift utilise une structure complexe à la place d'un objet Objective-C, donc les comparaisons de tri n'ont pas besoin de répartitions de méthodes dynamiques (car elles ne peuvent pas être sous-classés) ou un travail de comptage de références (car il s'agit d'un type de valeur).

(Dans Objective-C, vous pouvez revenir à C/C++ pour les performances tant qu'il n'implique pas d'objets Objective-C, par exemple trier un tableau C de structures.)

5
Jerry101

Honnêtement, à moins qu'ils ne libèrent la source des tests qu'ils utilisent, je ne ferais confiance à rien Apple a à dire sur le sujet. N'oubliez pas, c'est la société qui est passée de PPC à Intel basé sur des problèmes d'alimentation quand 6 mois plus tôt, ils disaient qu'Intel avait sucé et incendié le lapin Intel dans une publicité. Je voudrais voir une preuve irréfutable que Swift est plus rapide qu'ObjC dans plus de catégories que le simple tri.

De plus, vous devez remettre en question toutes les statistiques publiées à la WWDC car elles ont l'odeur du marketing partout.

Tout cela étant dit, je n'ai exécuté aucun test entre Swift et ObjC moi-même, mais d'après ce que je sais Swift a ses propres extensions IR LLVM et il il est possible que plus d'optimisation soit effectuée au moment de la compilation qu'en ObjC.

Divulgation complète: J'écris un open source Swift situé à https://ind.ie/phoenix/

Si quelqu'un souhaite aider à s'assurer que Swift n'est pas seulement disponible sur le matériel Apple, faites le moi savoir et je serais heureux de vous inclure).

3
greg.casamento

Je me suis battu à travers le tutoriel Swift, et il me semble que Swift est plus terre à terre (me fait penser à Visual Basic) avec moins 'object-ification' qu'Objective-C. S'ils avaient pris en compte le C ou le C++, je suppose que ce dernier aurait gagné, car ils sont encore plus à la compilation.

Dans ce cas, je suppose que Objective-C est victime de sa pureté orientée objet (et de ses frais généraux).

0
Painted Black