L'interprétation d'un test en C, Clojure, Python, Ruby, Scala et les autres
Avertissement
Je sais que les indices de référence sont le mal. Ils peuvent afficher uniquement les résultats pour des cas très particuliers étroit de la situation. Je ne suppose pas qu'une langue est mieux que les autres en raison de la certains stupide banc. Cependant je me demande pourquoi les résultats sont si différents. Veuillez voir mes questions au fond.
Math référence description
Indice de référence des calculs mathématiques simples pour trouver des paires de nombres premiers qui diffèrent par 6 (dite sexy nombres premiers)
E. g. sexy nombres premiers inférieurs à 100 serait: (5 11) (7 13) (11 17) (13 19) (17 23) (23 29) (31 37) (37 43) (41 47) (47 53) (53 59) (61 67) (67 73) (73 79) (83 89) (97 103)
Tableau des résultats de la
Dans le tableau: temps de calcul en secondes
En cours d'exécution: tous sauf le Facteur était en cours d'exécution dans VirtualBox (la version unstable de Debian amd64 invité, Windows 7 x64 accueil)
PROCESSEUR: AMD A4-3305M
Sexy primes up to: 10k 20k 30k 100k
Bash 58.00 200.00 [*1] [*1]
C 0.20 0.65 1.42 15.00
Clojure1.4 4.12 8.32 16.00 137.93
Clojure1.4 (optimized) 0.95 1.82 2.30 16.00
Factor n/a n/a 15.00 180.00
Python2.7 1.49 5.20 11.00 119
Ruby1.8 5.10 18.32 40.48 377.00
Ruby1.9.3 1.36 5.73 10.48 106.00
Scala2.9.2 0.93 1.41 2.73 20.84
Scala2.9.2 (optimized) 0.32 0.79 1.46 12.01
[*1] - j'ai peur d'imaginer combien de temps cela prend-il
Listes de Code
C:
int isprime(int x) {
int i;
for (i = 2; i < x; ++i)
if (x%i == 0) return 0;
return 1;
}
void findprimes(int m) {
int i;
for ( i = 11; i < m; ++i)
if (isprime(i) && isprime(i-6))
printf("%d %d\n", i-6, i);
}
main() {
findprimes(10*1000);
}
Ruby:
def is_prime?(n)
(2...n).all?{|m| n%m != 0 }
end
def sexy_primes(x)
(9..x).map do |i|
[i-6, i]
end.select do |j|
j.all?{|j| is_prime? j}
end
end
a = Time.now
p sexy_primes(10*1000)
b = Time.now
puts "#{(b-a)*1000} mils"
Scala:
def isPrime(n: Int) =
(2 until n) forall { n % _ != 0 }
def sexyPrimes(n: Int) =
(11 to n) map { i => List(i-6, i) } filter { _ forall(isPrime(_)) }
val a = System.currentTimeMillis()
println(sexyPrimes(100*1000))
val b = System.currentTimeMillis()
println((b-a).toString + " mils")
Scala opimized isPrime
(la même idée comme en Clojure optimisation):
import scala.annotation.tailrec
@tailrec //Not required, but will warn if optimization doesn't work
def isPrime(n: Int, i: Int = 2): Boolean =
if (i == n) true
else if (n % i != 0) isPrime(n, i + 1)
else false
Clojure:
(defn is-prime? [n]
(every? #(> (mod n %) 0)
(range 2 n)))
(defn sexy-primes [m]
(for [x (range 11 (inc m))
:let [z (list (- x 6) x)]
:when (every? #(is-prime? %) z)]
z))
(let [a (System/currentTimeMillis)]
(println (sexy-primes (* 10 1000)))
(let [b (System/currentTimeMillis)]
(println (- b a) "mils")))
Clojure optimisé is-prime?
:
(defn ^:static is-prime? [^long n]
(loop [i (long 2)]
(if (= (rem n i) 0)
false
(if (>= (inc i) n) true (recur (inc i))))))
Python
import time as time_
def is_prime(n):
return all((n%j > 0) for j in xrange(2, n))
def primes_below(x):
return [[j-6, j] for j in xrange(9, x+1) if is_prime(j) and is_prime(j-6)]
a = int(round(time_.time() * 1000))
print(primes_below(10*1000))
b = int(round(time_.time() * 1000))
print(str((b-a)) + " mils")
Facteur
MEMO:: prime? ( n -- ? )
n 1 - 2 [a,b] [ n swap mod 0 > ] all? ;
MEMO: sexyprimes ( n n -- r r )
[a,b] [ prime? ] filter [ 6 + ] map [ prime? ] filter dup [ 6 - ] map ;
5 10 1000 * sexyprimes . .
Bash(zsh):
#!/usr/bin/zsh
function prime {
for (( i = 2; i < $1; i++ )); do
if [[ $[$1%i] == 0 ]]; then
echo 1
exit
fi
done
echo 0
}
function sexy-primes {
for (( i = 9; i <= $1; i++ )); do
j=$[i-6]
if [[ $(prime $i) == 0 && $(prime $j) == 0 ]]; then
echo $j $i
fi
done
}
sexy-primes 10000
Questions
- Pourquoi Scala est si vite? C'est à cause de le typage statique? Ou c'est juste à l'aide de la JVM de manière très efficace?
Pourquoi une telle différence entre Ruby et Python? Je pensais que ces deux ne sont pas un peu complètement différent. Peut-être que mon code est faux. Merci de m'éclairer! Merci.UPD Oui, c'était une erreur dans mon code. Python et Ruby 1.9 sont assez égale.- Vraiment impressionnant saut de productivité entre les versions Rubis.
- Puis-je optimiser Clojure code par adjonction de ce type de déclarations? Il va les aider?
- 1) Votre question n'est pas un bon ajustement pour DONC, à mon humble avis. 2) Pourquoi vous n'avez pas fourni Clojure et Scala versions?
- Je veux dire que les versions linguistiques, comme 2.8, 2.9, ...
- Pourriez-vous ajouter vos options de compilation pour chaque langue?
- Non pas qu'il n'a rien à voir avec vos contrôles de performances, mais à partir d'un algorithme de point de vue, vous avez vraiment besoin de vérifier quelque chose comme
n/2
de savoir s'il est premier ou non (bien qu'il ne sera probablement pas faire une énorme différence). - Si vous jetez un oeil à shootout.alioth.debian.org vous trouverez que vos résultats sont tous dans le typique par rapport plages
- en fait jusqu'à
sqrt(n)
mais qui peut prendre un certain temps à calculer. Aussi votre code C imprime les primes comme il les trouve, alors que vos autres langues de calcul dans les listes et les imprime ensuite les sortir. Alors que C est sans surprise le plus rapide, vous pourriez être en mesure de l'obtenir plus rapidement. - vraiment,
sqrt(n)
? Je suppose que le sens ... Génial. Je souhaite que je pourrais préféré commentaire, donc je me souviendrai toujours (ou au moins être en mesure de le trouver). Je pensais naïvement c'est pourquoi j'ai ditn/2
(qui est juste un peu de décalage, donc ça devrait être rapide à calculer). - (Et bien sûr, le Crible d'Eratosthène .. mais ce micro-benchmark est un peu un test de stress de l'itération et des opérations mathématiques. Cependant, ils ne sont toujours pas "juste" comme dans certains sont plus paresseux.)
- Pourrais-je vous envoyer un Aller à la source pour que vous exécutez sur votre VirtualBox? Je suis très rapide sur mon ordinateur portable, mais il est évidemment très différente de la configuration et je voudrais savoir comment il se compare à d'autres langues, sous votre configuration.
- J'ai juste couru mon Go version et votre version de C (qui ressemblent beaucoup aussi) et j'ai pratiquement eu la même vitesse dans les deux d'entre eux. J'ai seulement essayé le 100k version:
C: 2.723s
Go: 2.743s
. - Avec 1000*1000 (1M au lieu de 100K):
C: 3m35.458s
Go: 3m36.259s
- Ajout d'une version de PHP. 100K:
PHP: 1m3.766s
Vraiment lent par rapport à C et. sqrt()
est généralement un bien optimisé fonction de la bibliothèque. Je pense que le coût d'un seulsqrt()
sur un seul flotteur valeur sera beaucoup moins cher que de le faire répétées module d'opérations qui ne sont pas nécessaires, et plus les chiffres en cours de vérification obtenir, plus les économies. Je viens d'essayer le code de ma réponse, et changé le vérifiersqrt()
justen - 1
et des temps d'exécution plus que doublé (de 19 secondes).- J'ai essayé votre optimisation (case à n/2), et de réduire le temps de moitié dans tous les cas. Évidemment, proportionnellement, le taux de rendement entre les langues est le même qu'avant, mais je pense que vous s'est avéré un point: en terme de performance, écriture intelligente code est plus important que de choisir un rapide de la langue.
- attendez jusqu'à ce que vous entendez à propos de déterministe variantes de Miller-Rabin test de primalité. Ils sont relativement simples à mettre en œuvre par exemple, Francky du code Python dans la discussion du problème 387 sur projecteuler.net.
- Pour le Facteur, veuillez jeter un oeil à
math.primes
vocabulaire. Il a déjà un très bien optimiséprime?
mot. - Vous n'avez pas besoin de calculer
sqrt
pour cette case. Vous pouvez calculer le carré dei
comme dansfor (i = 2; i * i <= x; ++i) ...
- pourrait se déplacer vers le codegolf.pile... et d'essayer de voir quelle langue est plus rapide, ou qui peut mettre en œuvre le plus rapide pour chaque langue, etc. Je pense qu'il serait intéressant de mieux voir les suggestions, il y
- Comparaisons de performances sont amusants, mais celui-ci, en particulier, s'appuyer sur une mise en application arbitraire des détails qui ne sont spécifiques à ce problème.
- Je vous suggère de les annoter Scala optimisé
isPrime
avec@tailrec
, pour vous assurer que vous êtes à l'aide de la queue de la récursivité. Il est facile, à tort, faire quelque chose qui empêche la queue de la récursivité, et cette annotation doit vous avertir si cela arrive. - Bon point! Pour le faire j'ai devrait
import scala.annotation.tailrec
- code Python qui utilise unoptimized Crible d'Eratosthène fonctionne en
0.03
secondes (30
millisecondes) pour100K
c'est à dire,500
fois plus rapide que la version C ci-dessus. - Ouais, c'est génial. Mais vous utilisez du meilleur algorithme. Le but était de comprendre comment bien peut-on optimiser le simple (stupide) de l'algorithme dans des langues différentes.
- Je comprends que. C'est pourquoi le commentaire de @ pst qui a fait état de cet algorithme.
- btw, tapé version de Python explicite pour la boucle est 15 à 20 fois plus rapide (accepté réponse pour Clojure utilise également des types). Cette version utilise exactement le même algorithme.
- J'ai posté résultats de l'exécution de l'indice de référence sur RPython, Pypy, Cython, Jython, Disponible 2.x, Disponible 3.
- Dans la version 11 qui pastebin d'erreur indique que vous devez avoir enlevé le
: Boolean
type de l'annotation de laisPrime
méthode (requis sur les méthodes récursives en raison de limitations dans l'inférence de type). Le site d'appel{ _ forall isPrime }
devrait être OK avec tout Scala version - J'ai ajouté un pur code C référence. Cython base de la variante a presque les mêmes performances que la C. Remarque: la seule différence entre le pur Python et Cython variantes est
@cython.locals(n=int, j=int)
décorateur qui raconte Cython sur les types statiques c'est à dire, il est semblable à l'optimisation de Clojure code à cet égard (mais plus rapide).
Vous devez vous connecter pour publier un commentaire.
Rugueux réponses:
(2...n).all?
dans la fonctionis-prime?
est susceptible d'être assez bien optimisé en Ruby (EDIT: on dirait que c'est effectivement le cas, voir Julian réponse pour plus de détails...)Plus important de l'optimisation dans le Clojure code serait d'utiliser tapé primitives mathématiques dans
is-prime?
, quelque chose comme:Avec cette amélioration, je reçois Clojure remplir 10k en 0.635 secondes (c'est à dire le deuxième plus rapide sur votre liste, en battant la Scala)
P. S. note que vous avez l'impression de code à l'intérieur de votre point de repère dans certains cas - pas une bonne idée car il va fausser les résultats, en particulier si vous utilisez une fonction comme
print
pour la première fois les causes de l'initialisation de IO sous-systèmes ou quelque chose comme ça!is-prime?
montre 2x amélioration. 😉(zero? (mod n i))
devrait être plus rapide que(= (mod n i) 0)
Voici un rapide Clojure version, en utilisant les mêmes algorithmes de base:
Il fonctionne environ 20x plus vite que votre original sur ma machine. Et voici une version qui s'appuie sur les nouveaux réducteurs de la bibliothèque en 1.5 (nécessite Java 7 ou JSR 166):
Cela fonctionne environ 40x plus rapide que celui de votre originaux. Sur ma machine, c'est 100k en 1,5 secondes.
unchecked-remainder-int
ou tout simplementrem
au lieu demod
avec le typage statique résultats à 4x augmentation de la performance. Nice!Je vais répondre simplement #2, car c'est le seul que j'ai quelque chose à distance intelligent à dire, mais pour votre code Python, vous êtes en train de créer un intermédiaire de liste dans
is_prime
, alors que vous êtes en utilisant.map
dans votreall
en Ruby, qui est juste de l'itération.Si vous modifiez votre
is_prime
à:ils sont à égalité.
J'ai pu optimiser le Python, mais mon Ruby n'est pas assez bon à savoir quand j'ai donné plus d'un avantage (par exemple, à l'aide de
xrange
rend Python gagner sur ma machine, mais je ne me souviens pas si la chaîne Ruby vous avez utilisé crée une gamme complète dans la mémoire ou pas).EDIT: Sans être trop ridicule, rendant le code Python ressembler à:
qui ne change pas beaucoup plus, il met à 1,5 s pour moi, et, avec en étant encore plus ridicule, de l'exécution avec PyPy, il met à .3s pour 10K, et de 21 ans pour 100K.
False
(bonne prise).xrange
! J'ai corrigé et maintenant, Python et Ruby montrer l'égalité des résultats.lru_cache
mise en œuvre pour 2,7 trouvé sur COMME, 100K s'exécute dans 2.3.s.(n%j != 0)
ou tout simplementn % j
peut être plus lisible que(n%j > 0)
is_prime(j)
etis_prime(j-6)
dansprimes_below
.)Vous pouvez faire de la Scala beaucoup plus vite en modifiant votre
isPrime
méthode pourPas tout à fait aussi concis mais le programme s'exécute à 40% du temps!
Nous couper le superflu
Range
et anonymeFunction
des objets, de la Scala compilateur reconnaît la queue-la récursivité et la transforme en un moment, en boucle, que la JVM peut se transformer en un plus ou moins optimal de code machine, de sorte qu'il ne devrait pas être trop loin de la version de C.Voir aussi: Comment optimiser pour des inclusions et des boucles en Scala?
i == n || n % i != 0 && isPrime(n, i + 1)
, qui est plus court, quoique un peu plus difficile à lire@tailrec
annotation, pour s'assurer qu'il va faire de cette optimisation.Voici mon scala version à la fois parallèles et non parallèles, juste pour le fun:
(Dans mon dual core de calcul, la version parallèle prend 335ms tandis que le no-version parallèle prend 655ms)
EDIT: Selon Emil Hla suggestion, j'ai modifié mon code pour éviter les effets de IO et de la jvm de chauffe:
Le résultat montre que dans mon calcul:
isSexyPrime
peut-être (plus) optimisé lorsqu'il est appelé à partir defindPrimesPar
et pas tellement lorsqu'il est appelé à partir defindPrimes
Jamais l'esprit les critères de référence; le problème m'a intéressé et j'ai fait un rapide réglages. Il utilise la
lru_cache
décorateur, qui memoizes une fonction; ainsi, lorsque nous appelonsis_prime(i-6)
essentiellement, nous obtenons que le premier contrôle de la liberté. Ce changement coupes le travail à peu près à la moitié. Aussi, nous pouvons faire larange()
appels étape à travers tout le nombres impairs, la réduction du travail à peu près de moitié à nouveau.http://en.wikipedia.org/wiki/Memoization
http://docs.python.org/dev/library/functools.html
Cela nécessite Python 3.2 ou plus récent pour obtenir
lru_cache
, mais pourrait fonctionner avec un plus vieux Python si vous installez un Python recette qui fournitlru_cache
. Si vous utilisez Python 2.x vous devriez vraiment utiliserxrange()
au lieu derange()
.http://code.activestate.com/recipes/577479-simple-caching-decorator/
Ci-dessus n'a pris que très peu de temps à modifier. J'ai décidé de prendre une nouvelle étape, et de faire les premiers test seulement essayer de diviseurs premiers, et seulement jusqu'à la racine carrée du nombre d'être testé. Je l'ai fait ne fonctionne que si vous vérifiez les numéros dans l'ordre, de sorte qu'il peut cumuler tous les nombres premiers comme il va; mais ce problème a déjà été cochant les numéros dans l'ordre, donc c'était bon.
Sur mon portable (rien de spécial; processeur est un processeur de 1,5 GHz AMD Turion II "K625"), cette version apporte une réponse à 100 en moins de 8 secondes.
Le code ci-dessus est assez facile d'écrire en Python, Ruby, etc. mais serait plus d'une douleur dans C.
Vous ne pouvez pas comparer les chiffres sur cette version à l'encontre de l'un des numéros de l'autre des versions sans avoir à réécrire les autres à utiliser des astuces similaires. Je ne cherche pas à prouver quoi que ce soit ici; j'ai juste pensé que le problème était amusant et j'ai voulu voir ce genre de représentation facile améliorations que j'ai pu glaner.
lru_cache
est certainement intéressante. Pour certaines classes de problèmes, tels que la génération de nombres de Fibonacci successifs, il peut donner une énorme accélération par le simple ajout d'une ligne décorateur sur la la fonction! Voici un lien vers un Raymond Hettinger parler qui couvrelru_cache
environ 26 minutes en. blip.tv/pycon-us-videos-2009-2010-2011/...lru_cache
évite la répétition d'un calcul qui a été déjà fait récemment, et c'est tout; je ne vois pas en quoi c'est "en fait, nous[ing], un algorithme". Et Python souffre peut-être lent, mais les avantages d'avoir des trucs sympas commelru_cache
; je ne vois rien de mal avec l'aide de véritables pièces d'une langue. Et je dit que l'on ne doit pas comparer le temps d'exécution de ma réponse contre les autres langues sans faire des changements similaires pour les autres. Donc, je ne comprends pas ce que tu veux dire.0.03
secondes (30
ms).N'oubliez pas de Fortran! (Surtout plaisanter, mais je m'attends à des performances similaires à C). Les énoncés avec des points d'exclamation sont facultatifs, mais un bon style. (
!
est un caractère de commentaire en fortran 90)Je ne pouvais pas résister à faire un peu de la plus évidente des optimisations pour la version C qui a fait le test 100k maintenant prendre 0,3 s sur ma machine (5 fois plus rapide que la version C de la question, à la fois compilé avec MSVC 2010 /Ox).
Ici est l'identique de la mise en œuvre en Java:
Avec Java 1.7.0_04 cela fonctionne presque aussi rapide que le C de la version. Le Client ou le serveur VM ne montre pas beaucoup de différence, sauf que JIT de la formation semble aider le serveur VM un peu (~3%) alors qu'il a presque pas d'effet avec le client VM. La sortie en Java semble être plus lent que dans C. Si la sortie est remplacé par un compteur statique dans les deux versions, la version Java tourne un peu plus vite que la version de C.
Ce sont mes temps pour le 100k exécuter:
et la 1M run (16386 résultats):
Alors que ce n'est pas vraiment répondre à vos questions, il montre que de petites modifications peuvent avoir un impact notable sur les performances. Donc, pour être en mesure de vraiment comparer les langues que vous devriez essayer d'éviter tous algorithmique différences autant que possible.
Il donne également un aperçu pourquoi Scala semble plutôt rapide. Il s'exécute sur la machine virtuelle Java, et donc des avantages à partir de ses performances impressionnantes.
En Scala essayez d'utiliser Tuple2 au lieu de la Liste, cela devrait aller plus vite. Il suffit de retirer le mot "Liste" puisque (x, y) est un Tuple2.
Tuple2 est spécialisé pour les Int, Long et Double sens, il n'aura pas de zone/unbox ces types de données brutes. Tuple2 source. La liste n'est pas spécialisé. Liste source.
forall
sur elle. J'ai aussi pensé que ce ne serait pas le code le plus efficace (plus parce que un grand stricte de la collection est créé pour les grandesn
au lieu de simplement en utilisant un point de vue), mais il est certainement court + élégant, et j'ai été surpris de voir comment il est effectué en dépit de l'aide de beaucoup de style fonctionnel.def sexyPrimes(n: Int) = (11 to n).map(i => (i-6, i)).filter({ case (i, j) => isPrime(i) && isPrime(j) })
c'est environ 60% plus rapide ici, devrait donc battre le code C 🙂filter((i, j) => isPrime(i) && isPrime(j))
est assez. Je voudrais aussi essayer(11 to n) collect { case i if isPrime(i-6) && isPrime(i) => (i-6, i) }
filter
reçoit unFunction1
dont l'argument est uneTuple2
qui doivent être extraites, vous ne pouvez pas utiliser unFunction2
. J'ai créé le tuple de la première, de sorte que lei-6
n'apparaît pas deux fois, mais certainement votre exemple aveccollect
fonctionne aussi bien.filter(p => isPrime(p._1) && isPrime(p._2))
doit avoir été est un peu laid.collect
sensiblement plus lent. Plus c'est rapide, si vous faites d'abord le filtre et ensuite la carte.withFilter
est légèrement plus rapide, car il ne fait pas de créer intermédiaire des collections.(11 to n) withFilter (i => isPrime(i - 6) && isPrime(i)) map (i => (i - 6, i))
Voici le code pour l'Aller (golang.org version:
Il a couru aussi vite que la version de C.
À l'aide d'un Asus u81a
Intel Core 2 Duo T6500 2.1 GHz, 2MB L2 cache, 800 mhz FSB.
4 GO DE RAM
Les 100k version:
C: 2.723s
Go: 2.743s
Avec 1000000 (1M au lieu de 100K):
C: 3m35.458s
Go: 3m36.259s
Mais je pense qu'il serait juste d'utiliser Go construit dans les capacités de multithreading et de comparer cette version à la version C (sans le multithreading), juste parce que c'est presque trop facile de faire du multithreading avec Go.
Mise à jour: j'ai fait une version parallèle à l'aide de Goroutines en Aller:
La version parallélisée utilisé en moyenne 2.743 secondes, exactement le même temps que la version normale utilisé.La version parallélisée achevé en 1.706 secondes. Il a utilisé moins de 1,5 Mo de RAM.
Une chose étrange: Mon dual core kubuntu 64 bits jamais atteint un sommet dans les deux noyaux. Il semblait Aller a l'aide d'une seule base.le Fixe avec un appel àruntime.GOMAXPROCS(4)
Mise à jour: j'ai couru le paralellized version 1M numéros.
l'Un de Mes coeurs de CPU est à 100% tout le temps, tandis que l'autre n'était pas utilisé à tous (impair). Il a fallu toute une minute de plus que le C et le régulier d'Aller les versions. 🙁Avec 1000000 (1M au lieu de 100K):
C: 3m35.458s
Go: 3m36.259s
Go using goroutines:
3m27.137s2m16.125s
Les 100k version:
C: 2.723s
Go: 2.743s
Go using goroutines: 1.706s
-O3
ou mieux.Juste pour le fun, voici, en parallèle, une version de Ruby.
Sur mon 1.8 GHz Core i5 MacBook Air, les résultats de performance sont:
Il ressemble à la JVM JIT est de donner des Rubis d'une belle amélioration des performances dans le cas par défaut, tandis que le vrai multithreading aide JRuby effectuer 50% plus rapide dans la partie filetée du cas. Ce qui est plus intéressant, c'est que JRuby 1.7 améliore la JRuby 1.6 score par une saine 17%!
Basé sur x4u réponse, j'ai écrit un scala version en utilisant la récursivité, et j'ai amélioré par seulement aller à la racine carrée à la place de x/2 pour le premier de la fonction de contrôle. Je reçois ~250ms pour 100k, et ~600ms pour 1M. Je suis allé de l'avant et est allé à 10M de ~6s.
Je suis aussi rentré et a écrit un CoffeeScript (JavaScript V8) version, qui obtient ~15ms pour 100k, 250ms pour 1M, et 6 sur 10 m, à l'aide d'un compteur (en ignorant I/O). Si j'allume la sortie il faut ~150ms pour 100k, 1s pour 1M, et 12 pour 10M. Ne pouvait pas utiliser la récursivité tail ici, malheureusement, j'ai donc eu à convertir en boucles.
La réponse à votre question n ° 1 est que, Oui, le JVM est incredably rapide et oui le typage statique permet de.
La JVM doit être plus rapide que C dans le long terme, peut-être même plus rapide que le "Normal" de l'assemblée de la langue--bien sûr, vous pouvez toujours la main d'optimiser l'assemblée à battre de rien en faisant manuel d'exécution du profilage et de la création d'une version distincte pour chaque PROCESSEUR, vous avez juste à être incroyablement bon et bien informé.
Les raisons pour Java de vitesse sont:
La JVM peut analyser votre code alors qu'il s'exécute, et la main de l'optimiser, par exemple, si vous aviez une méthode qui pourrait être analysé de manière statique au moment de la compilation pour être une vraie fonction et la JVM remarqué que vous avez été souvent à l'appeler avec les mêmes paramètres, il POURRAIT en fait d'éliminer l'appel complètement et simplement injecter les résultats du dernier appel (je ne suis pas sûr si Java en fait cela exactement, mais il fais beaucoup de trucs de ce genre).
En raison de typage statique, la JVM peut savoir beaucoup de choses sur votre code au moment de la compilation, ce qui permet le pré-optimiser mal de trucs un peu. Cela permet également au compilateur d'optimiser chaque classe individuellement, sans la connaissance de la façon dont une autre classe est pour l'utiliser. Aussi Java n'est pas arbitraire des pointeurs à l'emplacement de la mémoire, il SAIT ce que les valeurs en mémoire peut et ne peut pas être modifié et peut optimiser en conséquence.
Tas de répartition est BEAUCOUP plus efficace que le C, le Java, le tas de l'allocation est plus comme C est pile l'allocation de vitesse--encore plus polyvalent. Beaucoup de temps est passé dans les différents algroithims utilisé ici, c'est un art--par exemple, tous les objets avec une courte durée de vie (comme C est pile variables) sont attribuées à une "connu" emplacement libre (pas de recherche d'une place libre, avec suffisamment d'espace) et sont tous libérés ensemble en une seule étape (comme une pile pop).
La JVM peut savoir bizarreries sur votre PROCESSEUR de l'architecture et de générer du code machine spécifiquement pour un CPU donnée.
La JVM peut accélérer votre code de temps après que vous avez envoyé. Un peu comme le déplacement d'un programme à un nouveau PROCESSEUR peut l'accélérer, de le déplacer vers une nouvelle version de la JVM peuvent également vous donner d'énormes records de vitesse taylored de Processeurs qui n'existait même pas lors de la première de compiler votre code, quelque chose c physiquement ne peut pas faire sans un recomiple.
Par la façon dont, plus de la mauvaise réputation de java vitesse vient le temps de démarrage long à charger la JVM (un Jour quelqu'un va construire la JVM dans l'OS, et cela ira loin!) et le fait que de nombreux développeurs sont vraiment mauvais à l'écriture de code de la GUI (surtout filetée), qui a causé Java Gui souvent insensible et glitch. Simple à l'utilisation des langues comme Java et VB ont leurs défauts amplifié par le fait que le capibilities de la programmeur moyen tend à être inférieure à la plus compliquée langues.