Go プログラムが大きすぎます。遅延初期化を使用できますか?
#会社の継続的な発展において、そのほとんどは当初は大規模な単一の事業体であり、変革は遅々として進みませんでした。規模は基本的に増加するプロセスです。
影響の一つは、パッケージ化されたアプリケーションのサイズがどんどん大きくなり、どこで使われるか分からないことです... 本日議論する提案「提案: 言語」 : 副作用なしでインポートできる遅延初期化インポート[1]》は、これに関連しています。
提案
背景
非常に単純な Go コードを観察して研究してみましょう。次のコード:
package main import _ "crypto/x509" func main() {}
この Go プログラムには 3 行のコードしかなく、何も含まれていないように見えます。これは実際にそうなのでしょうか?
次のコマンドを実行して初期化プロセスを確認できます:
$ go build --ldflags=--dumpdep main.go 2>&1 | grep inittask
出力結果:
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 ...
このプログラムは実際に多くのソフトウェア パッケージ (標準ライブラリ、3 番目) を初期化します。パーティーパッケージなど)。これにより、パッケージ サイズが標準の 1.3 MB から 2.3 MB に変更されます。
一定の規模では、その影響は非常に高くつくと考えられます。なぜなら、3 行 Go プログラムが実質的なことを何もしていないことがわかるからです。
起動パフォーマンスに敏感なプログラムはさらに不快になり、通常のプログラムも時間の経過とともに悪循環に陥り、起動が通常より遅くなります。
提案
解決策の面では、これを別の提案「提案: 仕様: Go 2: 手動制御を許可する」と組み合わせました。インポートされたパッケージの初期化について #[2]>>一緒に見てみましょう。
中心となるアイデアは、業界では遅延読み込みとも呼ばれる遅延初期化 (遅延 init) を導入することです。つまり、実際のインポートは必要に応じて行われ、パッケージが導入されていない時点で初期化が完了します。 最適化の方向: 主に、パッケージ パスのインポート後に遅延初期化ステートメントを追加します (後述の go:lazyinit または go:deferred アノテーションなど)。プログラムを正式に初期化する前に、プログラムが実際に使用されるまで待ってください。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 会把版本清单都整理出来,最终得到一个构建清单。
如下图:

ビルドされた最終的な依存関係バージョンは、予想と矛盾する可能性が高く、多くのビジネス上の問題を引き起こすことがわかります。最も典型的な問題は、grpc-go、protoc-go、etcd のマルチバージョン互換性の問題であり、多くの人を悩ませています。
この分野の囲碁チームの設計は比較的理想的であり、曹達もこれを囲碁モジュールの七つの大罪の 1 つとして分類しました。ソフトウェア パッケージの init 関数には、ランダムな初期化に関する多くの問題がありますが、これも少し馴染みのあるものです。
概要
この問題に対する解決策 (提案) はまだ議論中です。明らかに Go チームは、ソフトウェア ライブラリの作成者が独自のコードを制約できることを望んでいます。いじらないで初期化してください。
遅延初期化を導入してみてはいかがでしょうか。どう思いますか?メッセージを残してコメント欄で議論することを歓迎します。
以上がGo プログラムが大きすぎます。遅延初期化を使用できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Go では、関数のライフ サイクルには定義、ロード、リンク、初期化、呼び出し、戻り値が含まれます。変数のスコープは関数レベルとブロック レベルに分割されますが、ブロック内の変数はブロック内でのみ表示されます。 。

Go では、正規表現を使用してタイムスタンプを照合できます。ISO8601 タイムスタンプの照合に使用されるような正規表現文字列をコンパイルします。 ^\d{4}-\d{2}-\d{2}T \d{ 2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ 。 regexp.MatchString 関数を使用して、文字列が正規表現と一致するかどうかを確認します。

Go では、gorilla/websocket パッケージを使用して WebSocket メッセージを送信できます。具体的な手順: WebSocket 接続を確立します。テキスト メッセージを送信します。 WriteMessage(websocket.TextMessage,[]byte("message")) を呼び出します。バイナリ メッセージを送信します。WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}) を呼び出します。

Go と Go 言語は、異なる特性を持つ別個の存在です。 Go (Golang とも呼ばれます) は、同時実行性、高速なコンパイル速度、メモリ管理、およびクロスプラットフォームの利点で知られています。 Go 言語の欠点としては、他の言語に比べてエコシステムが充実していないこと、構文が厳格であること、動的型付けが欠如していることが挙げられます。

メモリ リークは、ファイル、ネットワーク接続、データベース接続などの使用されなくなったリソースを閉じることによって、Go プログラムのメモリを継続的に増加させる可能性があります。弱参照を使用してメモリ リークを防ぎ、強参照されなくなったオブジェクトをガベージ コレクションの対象にします。 go coroutine を使用すると、メモリ リークを避けるために、終了時にコルーチンのスタック メモリが自動的に解放されます。

IDE を使用して Go 関数のドキュメントを表示する: 関数名の上にカーソルを置きます。ホットキーを押します (GoLand: Ctrl+Q; VSCode: GoExtensionPack をインストールした後、F1 キーを押して「Go:ShowDocumentation」を選択します)。

Golang では、エラー ラッパーを使用して、元のエラーにコンテキスト情報を追加することで新しいエラーを作成できます。これを使用すると、さまざまなライブラリまたはコンポーネントによってスローされるエラーの種類を統一し、デバッグとエラー処理を簡素化できます。手順は次のとおりです。errors.Wrap 関数を使用して、元のエラーを新しいエラーにラップします。新しいエラーには、元のエラーのコンテキスト情報が含まれています。 fmt.Printf を使用してラップされたエラーを出力し、より多くのコンテキストとアクション性を提供します。異なる種類のエラーを処理する場合は、errors.Wrap 関数を使用してエラーの種類を統一します。

並行関数の単体テストは、同時環境での正しい動作を確認するのに役立つため、非常に重要です。同時実行機能をテストするときは、相互排他、同期、分離などの基本原則を考慮する必要があります。並行機能は、シミュレーション、競合状態のテスト、および結果の検証によって単体テストできます。
