Vaut-il la peine de passer de Python à Nim pour les performances?

Nim est un mélange de syntaxe Python et de performances C







Il y a quelques semaines, je parcourais GitHub et suis tombé sur un curieux référentiel: le projet était entièrement écrit en Nim . Je ne l’avais jamais rencontré auparavant, et cette fois, j’ai décidé de savoir de quel genre d’animal il s’agissait.



Au début, je pensais que j'étais en retard, que c'était l'un des langages de programmation courants que beaucoup, contrairement à moi, utilisent activement. Et puis j'ai décidé de l'étudier.



Voici mes conclusions:



  • Cette langue est en fait populaire parmi un cercle restreint de personnes.
  • Il devrait peut-être en être ainsi.


Donc, je vais vous parler un peu de mon expérience avec Nim, parler brièvement des fonctionnalités de programmation, et essayer également de le comparer avec Python et C. Pour l'avenir, je note que ce langage me semble très prometteur.



Codez en studio!



A titre d'exemple, j'ai décidé d'écrire quelque chose de plus complexe dans Nim que bonjour, monde:







cela ne semble rien de superflu, non? Cela semble si simple que vous pouvez facilement comprendre ce qu'il fait, même si vous n'avez jamais entendu parler de Nim auparavant. (Le programme affichera: "num: 5 i: 5")



Alors, analysons ce qui nous semble familier de quelque part.



Déclaration de variable



Ceci est douloureusement familier aux développeurs JavaScript. Alors que certains langages utilisent var et certains utilisent let, JS et Nim vous permettent d'utiliser les deux lors de la déclaration de variables. Cependant, il est important de noter qu'ils fonctionnent différemment dans Nim et dans JS. Mais plus là-dessus plus tard.



Blocs



Pour désigner un nouveau bloc dans Nim, nous utilisons un deux-points suivi d'une ligne en retrait. Tout est comme en Python.



Mots clés



Les deux boucles et l'instruction if semblent être un morceau de code Python. En fait, tout à partir de la ligne 5 est du code Python (en supposant que la fonction d'écho soit définie).



Alors oui, de nombreux mots-clés et opérateurs Python peuvent également être utilisés dans Nim: not, is, et, ou, etc.



Autrement dit, jusqu'à présent, nous ne voyons rien de spécial dans Nim: la pire version de Python (en termes de

syntaxe), compte tenu du fait que vous devez utiliser let ou var pour déclarer des variables.



Nous pourrions nous arrêter là, mais il y a un gros «mais»: Nim est un langage à typage statique qui fonctionne presque aussi vite que le langage C.



Eh bien, maintenant une autre conversation. Regardons ça.



Test de performance







Avant de plonger dans la syntaxe de Nim (en particulier la partie typée statiquement que nous n'avons pas vue jusqu'à présent), essayons d'évaluer ses performances. Pour ce faire, j'ai écrit une implémentation naïve pour calculer le nième nombre de Fibonacci en Nim, Python et C.Pour que



les choses soient justes, j'ai standardisé l'implémentation basée sur la solution Leetcode (Option 1) et essayé de la respecter le plus strictement possible dans les trois langues.



Vous pouvez bien sûr me rappeler LRU Cache . Mais pour l'instant, ma tâche est d'utiliser une approche standard, et non d'essayer d'optimiser les calculs. J'ai donc choisi une implémentation naïve.


Voici les résultats du calcul du 40e nombre de Fibonacci:







Oui, à proprement parler, l'expérience ne peut pas être qualifiée de pure, mais cela est en corrélation avec les résultats d'autres passionnés qui ont fait des tests plus sérieux [1] [2] [3] .



Tout le code que j'ai écrit pour cet article est disponible sur GitHub, y compris des instructions sur la façon d'exécuter cette expérience.



Alors pourquoi Nim est-il tellement plus rapide que Python?



Eh bien, je dirais qu'il y a deux raisons principales:



  1. Nim est un langage compilé et Python est un langage interprété (plus à ce sujet ici ). Cela signifie que plus de travail est effectué lorsque vous exécutez un programme Python car le programme doit être interprété avant de pouvoir s'exécuter. Cela rend généralement la langue plus lente.
  2. Nim est typé statiquement. Bien qu'il n'y ait pas de déclaration de type dans l'exemple que j'ai montré précédemment, nous verrons plus tard qu'il s'agit bien d'un langage typé statiquement. Dans le cas de Python, qui est typé dynamiquement, l'interpréteur a beaucoup plus de travail à faire pour définir et gérer les types de manière appropriée. Cela réduit également les performances.


La vitesse de travail augmente - la vitesse de codage diminue



Voici ce que dit la documentation Python sur les langages interprétés:

« / , , ».


C'est une bonne généralisation du compromis entre Python et C, par exemple. Tout ce que vous pouvez faire en Python, vous pouvez le faire en C, mais votre programme C fonctionnera plusieurs fois plus rapidement.



Mais vous passerez beaucoup plus de temps à écrire et à déboguer votre code C, il sera lourd et moins lisible. Et c'est pourquoi C n'est plus en demande et Python est populaire. En d'autres termes, Python est beaucoup plus simple (comparativement, bien sûr).



Donc, si Python est à une extrémité du spectre et C est à l'autre, alors Nim essaie d'arriver quelque part au milieu. C'est beaucoup plus rapide que Python, mais pas aussi difficile à programmer que C.



Jetons un coup d'œil à notre implémentation du calcul des nombres de Fibonacci.



DE:



#include <stdio.h>
int fibonacci(int n) {
    if (n <= 1) {
        return n;
    } 
    return fibonacci(n-1) + fibonacci(n-2);
}

int main(void) {
    printf("%i", fibonacci(40));
}


Python:



def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(40))


Nim:



proc fibonacci(n: int): int = 
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

echo(fibonacci(40))


Bien que Nim utilise le signe "=" dans sa syntaxe de procédure (fonction), il est en général beaucoup plus facile d'écrire du code qu'en C.



Peut-être est-ce vraiment un bon compromis? Un peu plus difficile à écrire que Python, mais cela fonctionne dix fois plus vite. Je pourrais vivre avec.



Syntaxe Nim



import strformat

#    https://nim-lang.org/

type
  Person = object
    name: string
    age: Natural #      

let people = [
  Person(name: "John", age: 45),
  Person(name: "Kate", age: 30)
]

for person in people:

  echo(fmt"{person.name} is {person.age} years old")


Je vais juste souligner les principales caractéristiques.



Variables



Nous utilisons var, let ou const pour déclarer des variables.



var et const fonctionnent de la même manière qu'en JavaScript, mais let est une histoire différente.



JavaScript let diffère de var en termes de portée, et Nim let désigne une variable dont la valeur ne peut pas changer après l'initialisation. Cela me ressemble à Swift.



Mais n'est-ce pas la même chose qu'une constante? - tu demandes.



Non. Dans Nim, la différence entre const et let est la suivante:

Pour const, le compilateur doit être en mesure de déterminer la valeur au moment de la compilation, tandis que pour let, elle peut être déterminée au moment de l'exécution.


Exemple de la documentation:



const input = readLine(stdin) # Error: constant expression expected
let input = readLine(stdin)   #  


Alternativement, les variables peuvent être déclarées et initialisées comme ceci:



var
   a = 1
   b = 2
   c = 3
   x, y = 10 #   x  y   10


Les fonctions



Les fonctions dans Nim sont appelées procédures:



proc procedureName(parameterName: parameterType):returnType =
   return returnVar


Étant donné que le langage est similaire à Python à bien des égards, les procédures semblent un peu étranges lorsque vous les voyez pour la première fois.



Utiliser "=" au lieu de "{" ou ":" est clairement déroutant. Tout va un peu mieux avec l'écriture de la procédure sur une seule ligne:



proc hello(s: string) = echo s


Vous pouvez également obtenir le résultat de la fonction:



proc toString(x: int): string =
   result =
       if x < 0: “negative”
       elif x > 0: “positive”
       else: “zero”


Il semble que vous deviez toujours renvoyer le résultat, mais dans ce cas, le résultat n'est pas une variable - c'est un mot-clé. Donc, l'extrait de code ci-dessus est correct du point de vue de Nim.



Vous pouvez également surcharger les procédures:




proc toString(x: int): string =   
    result =     
        if x < 0: "negative"     
        elif x > 0: "positive"     
        else: "zero"  
proc toString(x: bool): string =   
    result =     
        if x: "yep"     
        else: "nope"
echo toString(true) #  "yep"
echo toString(5) #  "positive"


Conditions et cycles



Cela a beaucoup à voir avec Python.



# if true:

# while true:

# for num in nums:


Pour parcourir une liste, par exemple, au lieu de range (), vous pouvez utiliser countup (début, fin) ou compte à rebours (début, fin) . Vous pouvez le faire encore plus facilement et utiliser for i in start..finish



Entrée et sortie utilisateur



let input = readLine(stdin)
echo input


Comparé à Python, readLine (stdin) est équivalent à input () et echo est équivalent à print.



echo peut être utilisé avec ou sans parenthèses.



Mon objectif est de vous donner une compréhension de base de Nim, et non de raconter toute sa documentation. Je me retrouve donc avec la syntaxe et je passe à d'autres fonctionnalités du langage.



Fonctionnalités supplémentaires



Programmation orientée objet



Nim n'est pas un langage orienté objet, mais il fournit un support minimal pour travailler avec des objets . Bien sûr, il est loin des classes Python.



Macros



Nim prend en charge les macros et la métaprogrammation, et les développeurs semblent mettre beaucoup l'accent sur cela. C'est le sujet de sa propre section de la série de trois leçons.



Petit exemple:



import macros  macro myMacro(arg: static[int]): untyped =  
   echo arg

myMacro(1 + 2 * 3)


Types de données de base



string, char, bool, int, uint  float.


Vous pouvez également utiliser ces types:



int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64


De plus, les chaînes de Nim sont des types mutables, contrairement à Python.



commentaires



Contrairement à Python, Nim utilise le caractère "#" en combinaison avec "[" et "]" pour les commentaires multilignes.



# a comment#[
a
multi
line
comment
]#


Compiler JavaScript



Nim peut traduire son code en JavaScript. Je ne sais pas si beaucoup de gens viennent pour l'utiliser. Mais il existe un exemple de jeu par navigateur de serpent écrit en Nim.



Itérateurs



Les itérateurs Nim ressemblent plus à des générateurs Python:



iterator countup(a, b: int): int =
   var res = a
   while res <= b:
       yield res
       inc(res)


Sensibilité à la casse et soulignement

Nim est sensible à la casse uniquement pour le premier caractère.



Autrement dit, il distingue HelloWorld et helloWorld, mais pas helloWorld, helloworld et hello_world. Par conséquent, la procédure suivante fonctionnera sans problème, par exemple:



proc my_func(s: string) =
   echo myFunc("hello")


Quelle est la popularité de Nim?







Nim a près de 10 000 étoiles sur GitHub. C'est un plus clair. Néanmoins, j'ai essayé d'estimer la popularité de la langue à partir d'autres sources et, bien sûr, ce n'est pas si élevé.



Par exemple, Nim n'a même pas été mentionné dans l' enquête 2020 Stack Overflow . Je n'ai pas pu trouver d'emplois de développeur Nim sur LinkedIn (même avec la géographie mondiale), et une recherche sur la balise [nim-lang] sur Stack Overflow n'a renvoyé que 349 questions (contre environ 1 500 000 pour Python ou 270 000 pour Swift)



. Ainsi, il serait juste de supposer que la plupart des développeurs ne l'ont pas utilisé et que beaucoup n'ont jamais entendu parler du langage Nim.



Remplacement de Python?



Pour être honnête, je pense que Nim est une langue assez cool. Pour écrire cet article, j'ai étudié le minimum requis, mais cela suffisait. Bien que je ne sois pas trop approfondi, je prévois d'utiliser Nim à l'avenir. Personnellement, je suis un grand fan de Python, mais j'aime aussi les langages typés statiquement. Donc, pour moi, l'amélioration des performances dans certains cas compense largement la légère redondance syntaxique.



Bien que la syntaxe de base soit très similaire à Python, elle est plus complexe. Par conséquent, la plupart des fans de Python ne seront probablement pas intéressés.



N'oubliez pas non plus la langue Go. Je suis sûr que beaucoup d'entre vous ont pensé à cela exactement comme vous l'avez lu, et à juste titre. Malgré le fait que la syntaxe de Nim soit plus proche de la syntaxe de Python, en termes de performances, il rivalise précisément avec des langages comme le "C ++ simplifié".

Une fois, j'ai testé les performances de Go. En particulier, pour Fibonacci (40), cela a fonctionné aussi vite que C.


Mais quand même: Nim peut-il rivaliser avec Python? J'en doute beaucoup. Nous constatons une tendance à l'augmentation des performances informatiques et à la simplification de la programmation. Et comme je l'ai noté, même si Nim offre un bon compromis syntaxe / performances, je ne pense pas que ce soit suffisant pour battre Python pur et polyvalent.

J'ai parlé avec l'un des développeurs Nim Core. Il pense que Nim convient mieux à ceux qui passent de C ++ qu'aux pythonistes.


Nim peut-il rivaliser avec Go? Peut-être (si Google "le permet"). Le langage Nim est aussi puissant que Go. De plus, Nim prend mieux en charge les fonctionnalités C / C ++, y compris les macros et la surcharge.



Mais plus à ce sujet la prochaine fois.






La publicité



Les serveurs Epic sont des serveurs virtuels abordables avec des processeurs AMD, une fréquence de cœur du processeur jusqu'à 3,4 GHz. La configuration maximale vous permettra d'obtenir le plein - 128 cœurs de processeur, 512 Go de RAM, 4000 Go de NVMe. Dépêchez-vous de commander!






All Articles