


Das Go-Programm ist zu groß. Können wir eine verzögerte Initialisierung verwenden?
Während sich das Unternehmen weiterentwickelt, sind die meisten von ihnen am Anfang große Einheiten, und die Transformation erfolgt langsam. Ein Lager wird länger als zehn Jahre genutzt, und die Größe des Lagers ist im Grunde ein Prozess der kontinuierlichen Steigerung.
Eine der Auswirkungen ist, dass die Größe der gepackten Anwendung immer größer wird und ich nicht weiß, wo sie verwendet wird ... Der Vorschlag, der heute besprochen wird „Vorschlag: Sprache: Lazy-Init-Importe nach möglicherweise Import ohne Nebenwirkungen [1]“ hängt damit zusammen.
Vorschlag
Hintergrund
Beobachten wir einen sehr einfachen Go-Code und studieren ihn. Der folgende Code:
package main import _ "crypto/x509" func main() {}
Dieses Go-Programm hat nur 3 Codezeilen und sieht nach nichts aus. Ist das tatsächlich der Fall?
Wir können den folgenden Befehl ausführen, um den Initialisierungsprozess zu sehen:
$ go build --ldflags=--dumpdep main.go 2>&1 | grep inittask
Ausgabeergebnis:
runtime.main -> runtime..inittask runtime.main -> main..inittask main..inittask -> crypto/x509..inittask crypto/x509..inittask -> bytes..inittask crypto/x509..inittask -> crypto/sha256..inittask crypto/x509..inittask -> encoding/pem..inittask crypto/x509..inittask -> errors..inittask crypto/x509..inittask -> sync..inittask crypto/x509..inittask -> crypto/aes..inittask crypto/x509..inittask -> crypto/cipher..inittask crypto/x509..inittask -> crypto/des..inittask ... context..inittask -> context.init.0 vendor/golang.org/x/net/dns/dnsmessage..inittask -> vendor/golang.org/x/net/dns/dnsmessage.init vendor/golang.org/x/net/route..inittask -> vendor/golang.org/x/net/route.init vendor/golang.org/x/net/route..inittask -> vendor/golang.org/x/net/route.init.0 ...
Dieses Programm initialisiert tatsächlich viele Softwarepakete (Standardbibliotheken, Pakete von Drittanbietern usw.). Dadurch ändert sich die Paketgröße von standardmäßig 1,3 MB auf 2,3 MB.
Ab einem gewissen Ausmaß glaubt jeder, dass diese Auswirkungen sehr teuer sind. Denn Sie sehen, dass das Go-Programm mit nur 3 Zeilen nichts Wesentliches bewirkt.
Programme, die empfindlich auf die Startleistung reagieren, werden mit der Zeit auch in einen Teufelskreis geraten und der Start wird langsamer als normal sein.
Lösung
Wir werden uns die Lösung zusammen mit einem weiteren Vorschlag ansehen „Vorschlag: Spezifikation: Go 2: Manuelle Kontrolle über die Initialisierung importierter Pakete zulassen[2]“.
Die Kernidee besteht darin, eine verzögerte Initialisierung (Lazy Init) einzuführen, die in der Branche auch häufig als Lazy Loading bezeichnet wird. Das heißt, der eigentliche Import erfolgt bei Bedarf und die Initialisierung ist abgeschlossen, wenn das Paket nicht eingeführt wird.
Optimierungsrichtung: Hauptsächlich Hinzufügen verzögerter Initialisierungsdeklarationen nach dem Importieren des Paketpfads, wie z. B. die unten erwähnten Annotationen go:lazyinit oder go:deferred. Warten Sie, bis das Programm tatsächlich verwendet wird, bevor Sie es offiziell initialisieren.
1、go:lazyinit 的例子:
package main import ( "crypto/x509" // go:lazyinit "fmt" ) func main() {...}
2、go:deferred 的例子:
package main import ( _ "github.com/eddycjy/core" // go:deferred _ "github.com/eddycjy/util" // go:deferred ) func main() { if os.Args[1] != "util" { // 现在要使用这个包,开始初始化 core, err := runtime.InitDeferredImport("github.com/some/module/core") ... } ... }
以此来实现,可以大大提高启动性能。
讨论
实际上在大多数的社区讨论中,对这个提案是又爱又恨。因为它似乎又有合理的诉求,但细思似乎又会发现完全不对劲。
这个提案的背景和解决方案,是治标不治本的。因为根本原因是:许多库滥用了 init 函数,让许多不必要的东西都初始化了。

Go 核心开发团队认为让库作者去修复这些库,而不是让 Go 来 “解决” 这些问题。如果支持惰性初始化,也会为这些低质量库的作者提供继续这样做的借口。
似曾相识的感觉
在写这篇文章时,我想起了 Go 的依赖管理(Go modules),其有一个设计是基于语义化版本的规范。
如下图

版本格式为 “主版本号.次版本号.修订号”,版本号的递增规则如下:
主版本号:当你做了不兼容的 API 修改。 次版本号:当你做了向下兼容的功能性新增。 修订号:当你做了向下兼容的问题修正。
Go modules 的原意是软件库都遵守这个规范,因此内部会有最小版本选择的逻辑。
也就是一个模块往往依赖着许多其它许许多多的模块,并且不同的模块在依赖时很有可能会出现依赖同一个模块的不同版本,Go 会把版本清单都整理出来,最终得到一个构建清单。
如下图:

Sie werden feststellen, dass die endgültige Abhängigkeitsversion wahrscheinlich nicht mit den Erwartungen übereinstimmt, was zu vielen Geschäftsproblemen führt. Das klassischste Problem ist das Kompatibilitätsproblem mit mehreren Versionen von grpc-go, protoc-go usw., unter dem viele Menschen leiden.
Das Design des Go-Teams in diesem Bereich ist relativ ideal und Cao Da hat es auch als eine der sieben Todsünden der Go-Module eingestuft. Die Init-Funktion des Softwarepakets hat viele Probleme mit der zufälligen Initialisierung, was auch ein wenig bekannt ist.
Zusammenfassung
Die Lösung (der Vorschlag) für dieses Problem wird noch diskutiert. Offensichtlich hofft das Go-Team, dass die Autoren der Softwarebibliothek ihren eigenen Code einschränken und nicht zufällig initialisieren können.
Wie wäre es Ihrer Meinung nach mit der Einführung einer verzögerten Initialisierung? Willkommen, um Nachrichten zu hinterlassen und im Kommentarbereich zu diskutieren.
Das obige ist der detaillierte Inhalt vonDas Go-Programm ist zu groß. Können wir eine verzögerte Initialisierung verwenden?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



In Go können WebSocket-Nachrichten mit dem Paket gorilla/websocket gesendet werden. Konkrete Schritte: Stellen Sie eine WebSocket-Verbindung her. Senden Sie eine Textnachricht: Rufen Sie WriteMessage(websocket.TextMessage,[]byte("message")) auf. Senden Sie eine binäre Nachricht: Rufen Sie WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}) auf.

In Go können Sie reguläre Ausdrücke verwenden, um Zeitstempel abzugleichen: Kompilieren Sie eine Zeichenfolge mit regulären Ausdrücken, z. B. die, die zum Abgleich von ISO8601-Zeitstempeln verwendet wird: ^\d{4}-\d{2}-\d{2}T \d{ 2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ . Verwenden Sie die Funktion regexp.MatchString, um zu überprüfen, ob eine Zeichenfolge mit einem regulären Ausdruck übereinstimmt.

In Go umfasst der Funktionslebenszyklus Definition, Laden, Verknüpfen, Initialisieren, Aufrufen und Zurückgeben; der Variablenbereich ist in Funktionsebene und Blockebene unterteilt. Variablen innerhalb einer Funktion sind intern sichtbar, während Variablen innerhalb eines Blocks nur innerhalb des Blocks sichtbar sind .

Speicherlecks können dazu führen, dass der Speicher des Go-Programms kontinuierlich zunimmt, indem: Ressourcen geschlossen werden, die nicht mehr verwendet werden, wie z. B. Dateien, Netzwerkverbindungen und Datenbankverbindungen. Verwenden Sie schwache Referenzen, um Speicherlecks zu verhindern, und zielen Sie auf Objekte für die Garbage Collection ab, wenn sie nicht mehr stark referenziert sind. Bei Verwendung von Go-Coroutine wird der Speicher des Coroutine-Stapels beim Beenden automatisch freigegeben, um Speicherverluste zu vermeiden.

Go und die Go-Sprache sind unterschiedliche Einheiten mit unterschiedlichen Eigenschaften. Go (auch bekannt als Golang) ist bekannt für seine Parallelität, schnelle Kompilierungsgeschwindigkeit, Speicherverwaltung und plattformübergreifende Vorteile. Zu den Nachteilen der Go-Sprache gehören ein weniger umfangreiches Ökosystem als andere Sprachen, eine strengere Syntax und das Fehlen dynamischer Typisierung.

Go-Funktionsdokumentation mit der IDE anzeigen: Bewegen Sie den Cursor über den Funktionsnamen. Drücken Sie den Hotkey (GoLand: Strg+Q; VSCode: Nach der Installation von GoExtensionPack F1 und wählen Sie „Go:ShowDocumentation“).

In Golang können Sie mit Fehler-Wrappern neue Fehler erstellen, indem Sie Kontextinformationen an den ursprünglichen Fehler anhängen. Dies kann verwendet werden, um die von verschiedenen Bibliotheken oder Komponenten ausgelösten Fehlertypen zu vereinheitlichen und so das Debuggen und die Fehlerbehandlung zu vereinfachen. Die Schritte lauten wie folgt: Verwenden Sie die Funktion „errors.Wrap“, um die ursprünglichen Fehler in neue Fehler umzuwandeln. Der neue Fehler enthält Kontextinformationen zum ursprünglichen Fehler. Verwenden Sie fmt.Printf, um umschlossene Fehler auszugeben und so mehr Kontext und Umsetzbarkeit bereitzustellen. Wenn Sie verschiedene Fehlertypen behandeln, verwenden Sie die Funktion „errors.Wrap“, um die Fehlertypen zu vereinheitlichen.

Das Testen gleichzeitiger Funktionen in Einheiten ist von entscheidender Bedeutung, da dies dazu beiträgt, ihr korrektes Verhalten in einer gleichzeitigen Umgebung sicherzustellen. Beim Testen gleichzeitiger Funktionen müssen grundlegende Prinzipien wie gegenseitiger Ausschluss, Synchronisation und Isolation berücksichtigt werden. Gleichzeitige Funktionen können Unit-Tests unterzogen werden, indem Rennbedingungen simuliert, getestet und Ergebnisse überprüft werden.
