Lohnt es sich, aus Leistungsgründen von Python auf Nim umzusteigen?

Nim ist eine Mischung aus Python-Syntax und C-Performance.







Vor einigen Wochen habe ich GitHub durchsucht und bin auf ein interessantes Repository gestoßen: Das Projekt wurde vollständig in der Nim- Sprache geschrieben . Ich war ihm noch nie begegnet und dieses Mal beschloss ich herauszufinden, was für ein Tier es war.



Zuerst dachte ich, dass ich hinter der Zeit zurückbleibe, dass dies eine der gängigen Programmiersprachen ist, die viele im Gegensatz zu mir aktiv verwenden. Und dann habe ich beschlossen, es zu studieren.



Hier sind meine Schlussfolgerungen:



  • Diese Sprache ist in einem engen Personenkreis sehr beliebt.
  • Vielleicht sollte es so sein.


Ich erzähle Ihnen ein wenig über meine Erfahrungen mit Nim, spreche kurz über die Programmierfunktionen und versuche, sie mit Python und C zu vergleichen. Mit Blick auf die Zukunft stelle ich fest, dass mir diese Sprache sehr vielversprechend erscheint.



Code im Studio!



Als Beispiel habe ich beschlossen, etwas Komplizierteres als Hallo Welt in Nim zu schreiben:







Es scheint nichts Überflüssiges zu sein, oder? Es scheint so einfach zu sein, dass Sie leicht herausfinden können, was es tut, selbst wenn Sie noch nie von Nim gehört haben. (Das Programm gibt Folgendes aus: "num: 5 i: 5")



Analysieren wir also, was uns von irgendwoher bekannt vorkommt.



Variable Aussage



Dies ist JavaScript-Entwicklern schmerzlich vertraut. Während einige Sprachen var und andere let verwenden, können Sie mit JS und Nim beide verwenden, wenn Sie Variablen deklarieren. Es ist jedoch wichtig zu beachten, dass sie in Nim anders funktionieren als in JS. Aber dazu später mehr.



Blöcke



Um einen neuen Block in Nim zu kennzeichnen, verwenden wir einen Doppelpunkt, gefolgt von einer eingerückten Linie. Alles ist wie in Python.



Stichworte



Beide Schleifen und die if-Anweisung scheinen ein Teil des Python-Codes zu sein. Tatsächlich ist alles ab Zeile 5 Python-Code (vorausgesetzt, wir haben die Echo-Funktion definiert).



Ja, viele Python-Schlüsselwörter und -Operatoren können auch in Nim verwendet werden: nicht, ist und oder oder und so weiter.



Das heißt, bis jetzt sehen wir in Nim nichts Besonderes: die schlechteste Version von Python (in Bezug auf die

Syntax), unter Berücksichtigung der Tatsache, dass Sie let oder var verwenden müssen, um Variablen zu deklarieren.



Wir könnten dort aufhören, aber es gibt ein großes "aber": Nim ist eine statisch typisierte Sprache, die fast so schnell funktioniert wie die C-Sprache.



Nun, jetzt noch ein Gespräch. Lass es uns überprüfen.



Leistungstest







Bevor wir uns mit der Syntax von Nim befassen (insbesondere mit dem statisch typisierten Teil, den wir bisher noch nicht gesehen haben), versuchen wir, seine Leistung zu bewerten. Zu diesem Zweck habe ich eine naive Implementierung zur Berechnung der n-ten Fibonacci-Zahl in Nim, Python und C geschrieben.



Um die Dinge fair zu halten, habe ich die Implementierung basierend auf der Leetcode- Lösung (Option 1) standardisiert und versucht, sie in allen drei Sprachen so streng wie möglich einzuhalten .



Sie können mich natürlich an LRU Cache erinnern . Im Moment besteht meine Aufgabe darin, einen Standardansatz zu verwenden und nicht zu versuchen, die Berechnungen zu optimieren. Also habe ich mich für eine naive Implementierung entschieden.


Hier sind die Ergebnisse für die Berechnung der 40. Fibonacci-Zahl:







Ja, genau genommen kann das Experiment nicht als rein bezeichnet werden, aber dies korreliert mit den Ergebnissen anderer Enthusiasten, die ernstere Tests durchgeführt haben [1] [2] [3] .



Der gesamte Code, den ich für diesen Artikel geschrieben habe, ist auf GitHub verfügbar , einschließlich Anweisungen zum Ausführen dieses Experiments.



Warum ist Nim so viel schneller als Python?



Nun, ich würde sagen, es gibt zwei Hauptgründe:



  1. Nim ist eine kompilierte Sprache und Python ist eine interpretierte Sprache (mehr dazu hier ). Dies bedeutet, dass mehr Arbeit geleistet wird, wenn ein Python-Programm ausgeführt wird, da das Programm interpretiert werden muss, bevor es ausgeführt werden kann. Dies macht die Sprache normalerweise langsamer.
  2. Nim ist statisch typisiert. Obwohl es in dem Beispiel, das ich zuvor gezeigt habe, keine Typdeklaration gab, werden wir später sehen, dass es sich tatsächlich um eine statisch typisierte Sprache handelt. Im Fall von Python, das dynamisch typisiert wird, muss der Interpreter viel mehr Arbeit leisten, um die Typen entsprechend zu definieren und zu behandeln. Es reduziert auch die Leistung.


Die Arbeitsgeschwindigkeit wächst - die Codierungsgeschwindigkeit nimmt ab



Folgendes sagen die Python-Dokumente zu interpretierten Sprachen:

« / , , ».


Dies ist beispielsweise eine gute Verallgemeinerung des Kompromisses zwischen Python und C. Alles, was Sie in Python tun können, können Sie in C tun, aber Ihr C-Programm wird um ein Vielfaches schneller ausgeführt.



Sie werden jedoch viel mehr Zeit damit verbringen, Ihren C-Code zu schreiben und zu debuggen. Er ist unhandlich und weniger lesbar. Und deshalb ist C nicht mehr gefragt und Python ist beliebt. Mit anderen Worten, Python ist viel einfacher (vergleichsweise natürlich).



Wenn sich Python an einem Ende des Spektrums und C am anderen befindet, versucht Nim, irgendwo in die Mitte zu gelangen. Es ist viel schneller als Python, aber nicht so schwer zu programmieren wie C.



Schauen wir uns unsere Implementierung zur Berechnung von Fibonacci-Zahlen an.



VON:



#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))


Obwohl Nim das Zeichen "=" in seiner Prozedur- (Funktions-) Syntax verwendet, ist es im Allgemeinen viel einfacher, Code zu schreiben als in C.



Vielleicht ist dies wirklich ein würdiger Kompromiss? Etwas schwieriger zu schreiben als Python, aber es funktioniert zehnmal schneller. Ich könnte damit leben.



Nim-Syntax



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")


Ich werde nur auf die Hauptmerkmale hinweisen.



Variablen



Wir verwenden var, let oder const, um Variablen zu deklarieren.



var und const funktionieren genauso wie in JavaScript, aber let ist eine andere Geschichte.



JavaScript let unterscheidet sich von var in Bezug auf den Umfang, und Nim let bezeichnet eine Variable, deren Wert sich nach der Initialisierung nicht ändern kann. Es sieht für mich aus wie Swift.



Aber ist das nicht dasselbe wie eine Konstante? - du fragst.



Nein. In Nim ist der Unterschied zwischen const und let wie folgt:

Für const muss der Compiler in der Lage sein, den Wert zur Kompilierungszeit zu bestimmen, während für let er zur Laufzeit bestimmt werden kann.


Beispiel aus der Dokumentation:



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


Alternativ können Variablen wie folgt deklariert und initialisiert werden:



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


Funktionen



Funktionen in Nim werden Prozeduren genannt:



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


Da die Sprache Python in vielerlei Hinsicht ähnlich ist, wirken die Prozeduren etwas seltsam, wenn Sie sie zum ersten Mal sehen.



Die Verwendung von "=" anstelle von "{" oder ":" ist eindeutig verwirrend. Alles ist ein bisschen besser, wenn Sie die Prozedur in eine Zeile schreiben:



proc hello(s: string) = echo s


Sie können auch das Ergebnis der Funktion erhalten:



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


Es fühlt sich so an, als müssten Sie das Ergebnis noch irgendwie zurückgeben, aber in diesem Fall ist das Ergebnis keine Variable - es ist ein Schlüsselwort. Das obige Code-Snippet ist also aus Nims Sicht korrekt.



Sie können Prozeduren auch überladen:




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"


Bedingungen und Zyklen



Es hat viel mit Python zu tun.



# if true:

# while true:

# for num in nums:


Um beispielsweise anstelle von range () eine Liste zu durchlaufen , können Sie Countup (Start, Ende) oder Countdown (Start, Ende) verwenden . Sie können es noch einfacher machen und für i in start..finish verwenden



Benutzereingabe und -ausgabe



let input = readLine(stdin)
echo input


Im Vergleich zu Python entspricht readLine (stdin) input () und echo entspricht print.



Echo kann mit oder ohne Klammern verwendet werden.



Mein Ziel ist es, Ihnen ein grundlegendes Verständnis von Nim zu vermitteln und nicht die gesamte Dokumentation erneut zu erzählen. Am Ende habe ich die Syntax und gehe zu anderen Funktionen der Sprache über.



Zusatzfunktionen



Objekt orientierte Programmierung



Nim ist keine objektorientierte Sprache, bietet jedoch nur minimale Unterstützung für die Arbeit mit Objekten . Natürlich ist er weit entfernt von Python-Klassen.



Makros



Nim unterstützt Makros und Metaprogrammierung, und die Entwickler scheinen großen Wert darauf zu legen. Dies ist das Thema eines eigenen Abschnitts der Drei-Lektionen-Reihe.



Kleines Beispiel:



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

myMacro(1 + 2 * 3)


Grundlegende Datentypen



string, char, bool, int, uint  float.


Sie können auch folgende Typen verwenden:



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


Außerdem sind Zeichenfolgen in Nim im Gegensatz zu Python veränderbare Typen.



Bemerkungen



Im Gegensatz zu Python verwendet Nim das Zeichen "#" in Kombination mit "[" und "]" für mehrzeilige Kommentare.



# a comment#[
a
multi
line
comment
]#


JavaScript kompilieren



Nim kann seinen Code in JavaScript übersetzen. Ich bin mir nicht sicher, ob viele Leute vorbeikommen, um dies zu nutzen. Aber es gibt ein solches Beispiel für das in Nim geschriebene Snake-Browsergame.



Iteratoren



Nim-Iteratoren ähneln eher Python-Generatoren:



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




Groß- und Kleinschreibung beachten und unterstreichen Nim unterscheidet nur zwischen Groß- und Kleinschreibung für das erste Zeichen.



Das heißt, es unterscheidet zwischen HelloWorld und helloWorld, aber nicht zwischen helloWorld, helloworld und hello_world. Daher funktioniert das folgende Verfahren beispielsweise problemlos:



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


Wie beliebt ist Nim?







Nim hat fast 10.000 Sterne auf GitHub. Dies ist ein klares Plus. Trotzdem habe ich versucht, die Popularität der Sprache aus anderen Quellen abzuschätzen, und natürlich ist sie nicht so hoch.



Zum Beispiel wurde Nim in der Stapelüberlauf-Umfrage 2020 nicht einmal erwähnt . Ich konnte keine Nim-Entwicklerjobs auf LinkedIn finden (selbst mit weltweiter Geografie) und eine Suche nach [nim-lang] bei Stack Overflow ergab nur 349 Fragen (im Vergleich zu ~ 1.500.000 für Python oder 270.000 für Swift)



. Man kann also davon ausgehen, dass die meisten Entwickler es nicht verwendet haben und viele noch nie von der Nim-Sprache gehört haben.



Python ersetzen?



Um ehrlich zu sein, denke ich, dass Nim eine ziemlich coole Sprache ist. Um diesen Artikel zu schreiben, habe ich das erforderliche Minimum studiert, aber das war genug. Obwohl ich mich nicht zu sehr damit befasst habe, plane ich, Nim in Zukunft zu verwenden. Persönlich bin ich ein großer Fan von Python, aber ich mag auch statisch typisierte Sprachen. Für mich macht die Leistungsverbesserung in einigen Fällen eine kleine syntaktische Redundanz mehr als wett.



Während die grundlegende Syntax Python sehr ähnlich ist, ist sie komplexer. Daher werden die meisten Python-Fans wahrscheinlich nicht daran interessiert sein.



Vergessen Sie auch nicht die Go-Sprache. Ich bin sicher, dass viele von Ihnen beim Lesen darüber nachgedacht haben, und das zu Recht. Trotz der Tatsache, dass die Syntax von Nim näher an der Syntax von Python liegt, konkurriert sie in Bezug auf die Leistung genau mit Sprachen wie "vereinfachtes C ++".

Ich habe einmal die Go-Leistung getestet. Insbesondere für Fibonacci (40) funktionierte es so schnell wie C.


Aber trotzdem: Kann Nim mit Python konkurrieren? Ich bezweifle es sehr. Wir sehen einen Trend zur Steigerung der Computerleistung und zur Vereinfachung der Programmierung. Und wie ich bereits erwähnt habe, denke ich nicht, dass es ausreicht, reines und vielseitiges Python zu schlagen, auch wenn Nim einen guten Kompromiss zwischen Syntax und Leistung bietet.

Ich habe mit einem der Nim Core-Entwickler gesprochen. Er ist der Meinung, dass Nim eher für Migranten aus C ++ als für Pythonisten geeignet ist.


Kann Nim mit Go konkurrieren? Möglicherweise (wenn Google "erlaubt"). Die Nim-Sprache ist so mächtig wie Go. Darüber hinaus bietet Nim eine bessere Unterstützung für C / C ++ - Funktionen, einschließlich Makros und Überladung.



Aber dazu irgendwann beim nächsten Mal mehr.






Werbung



Epic Server sind kostengünstige virtuelle Server mit Prozessoren von AMD, einer CPU-Kernfrequenz von bis zu 3,4 GHz. Die maximale Konfiguration ermöglicht es Ihnen, die vollen 128 CPU-Kerne, 512 GB RAM, 4000 GB NVMe zu erreichen. Beeilen Sie sich, um zu bestellen!






All Articles