Heim  >  Artikel  >  Backend-Entwicklung  >  Ist go eine interpretierte Sprache?

Ist go eine interpretierte Sprache?

青灯夜游
青灯夜游Original
2021-03-16 11:08:135378Durchsuche

go ist eine interpretierte Sprache. Go (auch bekannt als Golang) ist eine von Google entwickelte statisch stark typisierte, kompilierte, gleichzeitige Programmiersprache mit Garbage-Collection-Funktionen. Die Vorteile der Go-Sprache: einfache Lernkurve, hohe Entwicklungs- und Betriebseffizienz, leistungsstarke Standardbibliothek, auf Sprachebene definierte Formatierung des Quellcodes usw.

Ist go eine interpretierte Sprache?

Die Betriebsumgebung dieses Tutorials: Windows 10-System, GO 1.18, Thinkpad T480-Computer.

Go (auch bekannt als Golang) ist eine statisch stark typisierte, kompilierte Sprache, die von Robert Griesemer, Rob Pike und Ken Thompson von Google entwickelt wurde.

Gos Syntax ähnelt der C-Sprache, aber die Deklaration von Variablen ist anders. Go unterstützt die Garbage Collection. Das Parallelmodell von Go basiert auf Tony Halls Communicating Sequential Process (CSP). Zu den anderen Sprachen, die ein ähnliches Modell verwenden, gehören Occam und Limbo, es verfügt jedoch auch über Funktionen von Pi-Operationen, wie z. B. die Kanalübertragung. Die Plugin-Unterstützung ist in Version 1.8 geöffnet, wodurch einige Funktionen nun dynamisch aus Go geladen werden können.

Im Vergleich zu C++ enthält Go keine Funktionen wie Aufzählungen, Ausnahmebehandlung, Vererbung, Generika, Behauptungen, virtuelle Funktionen usw., fügt jedoch Unterstützung für Slice-Typ, Parallelität, Pipes, Garbage Collection und Schnittstellen hinzu für andere Funktionen. Die Go 2.0-Version unterstützt Generika, hat aber eine negative Haltung gegenüber der Existenz von Behauptungen und verteidigt sich auch dafür, dass sie keine Typvererbung bereitstellt.

Im Gegensatz zu Java verfügt Go über integrierte assoziative Arrays (auch Hashes oder Wörterbücher genannt), genau wie String-Typen. Vorteile der Go-Sprache der Syntax und schreiben Sie in wenigen Tagen Ihr erstes richtiges Programm. Lesen und verstehen Sie die praktische Go-Programmierung, durchsuchen Sie die Paketdokumentation, spielen Sie mit Web-Toolkits wie Gorilla oder Go Kit, und Sie werden ein ziemlich guter Go-Entwickler sein.

Das liegt daran, dass das Hauptziel von Go die Einfachheit ist. Als ich anfing, Go zu lernen, erinnerte es mich an meine erste Entdeckung von Java: eine einfache Sprache und eine umfangreiche, aber nicht aufgeblähte Standardbibliothek. Verglichen mit der aktuellen Java-lastigen Umgebung ist das Erlernen von Go eine erfrischende Erfahrung. Aufgrund der Einfachheit von Go sind Go-Programme sehr gut lesbar, obwohl die Fehlerbehandlung einige Kopfschmerzen bereitet (mehr dazu weiter unten). Die Einfachheit der Go-Sprache kann ein Fehler sein. Um Rob Pike zu zitieren: Einfachheit ist sowohl komplex als auch wir werden sehen, dass es viele Fallen gibt, die darauf warten, dass wir hinter die Einfachheit treten und dazu führen, dass wir gegen das DRY-Prinzip (Don't Repeat Yourself) verstoßen.

Einfache gleichzeitige Programmierung basierend auf Goroutinen und Kanälen

Goroutinen sind wahrscheinlich die beste Funktion von Go. Es handelt sich um leichtgewichtige Computing-Threads, die sich von Betriebssystem-Threads unterscheiden.

Wenn ein Go-Programm einen Vorgang ausführt, der scheinbar E/A blockiert, unterbricht die Go-Laufzeit die Goroutine tatsächlich und setzt sie fort, wenn ein Ereignis anzeigt, dass ein Ergebnis verfügbar ist. In der Zwischenzeit ist die Ausführung weiterer Goroutinen geplant. Daher verfügen wir im Rahmen des synchronen Programmiermodells über die Skalierbarkeitsvorteile der asynchronen Programmierung.

Goroutinen sind außerdem leichtgewichtig: Ihre Stapel wachsen und schrumpfen mit der Nachfrage, sodass es kein Problem ist, Hunderte oder sogar Tausende von Goroutinen zu haben.

Ich hatte eine Goroutine-Schwachstelle in meiner alten Anwendung: Diese Goroutinen warteten darauf, dass ein Kanal geschlossen wurde, bevor sie fertig wurden, und der Kanal wurde nie geschlossen (ein häufiges Deadlock-Problem). Dieser Prozess frisst ohne Grund 90 % der CPU, und die Überprüfung von expvars zeigt 600.000 inaktive Goroutinen. Ich vermute, dass der Goroutine-Scheduler die CPU überlastet.

Sicher, Akteursysteme wie Akka können problemlos mit Millionen von Akteuren umgehen, teilweise weil Akteure keine Stacks haben, aber sie sind bei weitem nicht so einfach wie Goroutinen zum Schreiben massiv gleichzeitiger Anforderungs-/Antwortanwendungen (d. h. http-APIs). Kanäle sind eine Möglichkeit für Goroutinen, zu kommunizieren: Sie bieten ein praktisches Programmiermodell zum Senden und Empfangen von Daten zwischen Goroutinen, ohne sich auf fragile Synchronisierungsprimitive auf niedriger Ebene verlassen zu müssen. Kanäle haben ihre eigenen Nutzungsmuster.

Kanäle müssen jedoch sorgfältig abgewogen werden, da Kanäle mit falscher Größe (die standardmäßig nicht gepuffert werden) zu Deadlocks führen können. Wir werden im Folgenden auch sehen, dass die Verwendung von Kanälen aufgrund der mangelnden Unveränderlichkeit keine Race Conditions verhindert.

Reichhaltige Standardbibliothek

Gos Standardbibliothek ist sehr umfangreich, insbesondere für alles, was mit der Netzwerkprotokoll- oder API-Entwicklung zu tun hat: http-Client und -Server, Verschlüsselung, Archivformate, Komprimierung, E-Mail-Versand und mehr. Es gibt sogar einen HTML-Parser und eine ziemlich leistungsstarke Template-Engine zum Generieren von Text und HTML, die automatisch XSS-Angriffe herausfiltert (wie sie in Hugo verwendet werden).

Verschiedene APIs sind im Allgemeinen einfach und leicht zu verstehen. Sie scheinen manchmal zu einfach zu sein: Dies liegt zum Teil daran, dass wir uns aufgrund des Goroutine-Programmiermodells nur um „scheinbar synchrone“ Vorgänge kümmern müssen. Das liegt auch daran, dass einige allgemeine Funktionen auch viele spezialisierte Funktionen ersetzen können, wie ich kürzlich über Zeitberechnungen erfahren habe.

Go bietet eine überlegene Leistung.

Go kompiliert in eine lokale ausführbare Datei. Viele Go-Benutzer kommen von Python, Ruby oder Node.js. Für sie ist dies eine aufregende Erfahrung, da sie einen enormen Anstieg der Anzahl gleichzeitiger Anfragen feststellen, die der Server verarbeiten kann. Das ist eigentlich ganz normal, wenn Sie eine interpretierte Sprache verwenden, die nicht gleichzeitig ist (Node.js) oder über eine globale Interpretersperre verfügt. In Kombination mit der Einfachheit der Sprache erklärt dies, warum Go spannend ist.

Im Vergleich zu Java ist das Bild bei reinen Leistungsbenchmarks jedoch nicht so klar. Wo Go Java übertrifft, liegt in der Speichernutzung und Garbage Collection.

Gos Garbage Collector ist darauf ausgelegt, Latenz zu priorisieren und Ausfallzeiten zu vermeiden, was besonders bei Servern wichtig ist. Dies kann zu höheren CPU-Kosten führen, aber in einer horizontal skalierbaren Architektur lässt sich dieses Problem leicht durch das Hinzufügen weiterer Maschinen lösen. Denken Sie daran, Go wurde von Google entwickelt und es mangelt ihnen nie an Ressourcen.

Gos Garbage Collector (GC) hat im Vergleich zu Java weniger zu tun: Ein Slice ist eine zusammenhängende Array-Struktur, kein Array von Zeigern wie Java. In ähnlicher Weise verwenden Go-Maps auch kleine Arrays als Buckets, um denselben Zweck zu erreichen. Dies bedeutet weniger Arbeit für den Garbage Collector und eine bessere Lokalisierung des CPU-Cache.

Go hat auch bei Befehlszeilendienstprogrammen einen Vorteil gegenüber Java: Als native ausführbare Datei haben Go-Programme keinen Startaufwand, während Java erfordert, dass zuerst Bytecode geladen und kompiliert wird.

Definieren der Quellcodeformatierung auf Sprachebene

Einige der hitzigsten Debatten in meiner Karriere fanden über die Definition der Codeformatierung in Teams statt. Go löst dieses Problem, indem es ein kanonisches Format für Code definiert. Das gofmt-Tool formatiert Ihren Code neu und bietet keine Optionen.

Ob es Ihnen gefällt oder nicht, gofmt definiert, wie Code formatiert wird, und löst so dieses Problem ein für alle Mal.

Standardisiertes Test-Framework

Go bietet in seiner Standardbibliothek ein gutes Test-Framework. Es unterstützt paralleles Testen und Benchmarking und enthält viele Dienstprogramme zum einfachen Testen von Netzwerk-Clients und -Servern.

Das Go-Programm ist einfach zu bedienen

Im Vergleich zu Python, Ruby oder Node.js ist die Installation einer einzigen ausführbaren Datei ein Traum für Betriebs- und Wartungsingenieure. Mit zunehmender Nutzung von Docker wird dieses Problem immer weniger, aber eigenständige ausführbare Dateien bedeuten auch kleine Docker-Images.

Go verfügt außerdem über einige integrierte Observability-Funktionen, die es ermöglichen, interne Status und Metriken mithilfe des expvar-Pakets zu veröffentlichen und das Hinzufügen neuer Inhalte zu vereinfachen. Seien Sie jedoch vorsichtig, da sie automatisch im Standard-HTTP-Request-Handler angezeigt werden und nicht geschützt sind. Java hat etwas Ähnliches wie JMX, ist aber viel komplexer.

Defer-Anweisung, um zu verhindern, dass das Aufräumen vergessen wird

Der Zweck der Defer-Anweisung ähnelt dem von Java: Bereinigungscode am Ende der aktuellen Funktion ausführen, unabhängig davon, wie diese Funktion beendet wird. Das Interessante an Defer ist, dass es keine Verbindung zum Codeblock hat und jederzeit erscheinen kann. Dadurch bleibt der Bereinigungscode so nah wie möglich an dem Code, der bereinigt werden muss :

file, err := os.Open(fileName)
if err != nil {
    return
}
defer file.Close()
// 用文件资源的时候,我们再也不需要考虑何时关闭它

Natürlich sind die Testressourcen von Java weniger ausführlich und Rust deklariert Ressourcen automatisch, wenn ihre Besitzer entfernt werden, aber da Go erfordert, dass Sie dies tun Es ist klar, was die Ressourcenbereinigung angeht, daher ist es schön, dass es in der Nähe der Ressourcenzuteilung steht.

Neue Typen

Ich liebe Typen, weil es einige Dinge gibt, die mich nerven und erschrecken, zum Beispiel geben wir persistente Objektbezeichner als String- oder lange Typen weiter. Normalerweise kodieren wir den ID-Typ im Parameternamen, aber das führt zu subtilen Fehlern, wenn eine Funktion mehrere Bezeichner als Parameter hat und einige Aufrufe nicht mit der Parameterreihenfolge übereinstimmen.

Go bietet erstklassige Unterstützung für neue Typen, d. h. der Typ ist ein vorhandener Typ und erhält eine unabhängige Identität, die sich vom ursprünglichen Typ unterscheidet. Im Gegensatz zum Paketieren haben neue Typen keinen Laufzeitaufwand. Dadurch kann der Compiler Fehler dieser Art abfangen:

type UserId string // <-- new type
type ProductId string
func AddProduct(userId UserId, productId ProductId) {}
func main() {
    userId := UserId("some-user-id")
    productId := ProductId("some-product-id")
    // 正确的顺序: 没有问题
    AddProduct(userId, productId)
    // 错误的顺序:将会编译错误 
    AddProduct(productId, userId)
    // 编译错误:
    // AddProduct 不能用 productId(type ProductId) 作为 type UserId的参数
    // Addproduct 不能用 userId(type UserId) 作为type ProfuctId 的参数 
}

Leider macht das Fehlen von Generika die Arbeit mit neuen Typen umständlich, da das Schreiben von wiederverwendbarem Code für sie das Konvertieren von Werten aus primitiven Typen erfordert.

Weitere Kenntnisse zum Thema Programmierung finden Sie unter: Programmiervideos! !

Das obige ist der detaillierte Inhalt vonIst go eine interpretierte Sprache?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn