Program Go terlalu besar. Bolehkah kita menggunakan pengamulaan malas?

Lepaskan: 2023-08-04 17:23:53
ke hadapan
804 orang telah melayarinya


Dalam pembangunan berterusan syarikat, kebanyakannya adalah unit yang besar pada mulanya, dan transformasinya perlahan Sebuah gudang akan digunakan selama lebih daripada sepuluh tahun, dan skala gudang itu pada asasnya a proses peningkatan berterusan.

Salah satu impaknya ialah saiz aplikasi yang dibungkus semakin besar dan saya tidak tahu di mana ia digunakan... Cadangan yang akan dibincangkan hari ini "proposal: bahasa: lazy init import ke mungkin import tanpa kesan sampingan [1]" adalah berkaitan dengan ini.

Cadangan

Latar Belakang

Mari kita perhatikan kod Go yang sangat mudah dan kajinya. Kod berikut:

package main

import _ "crypto/x509"

func main() {}
Salin selepas log masuk

Program Go ini hanya mempunyai 3 baris kod dan tidak kelihatan seperti apa-apa. Adakah ini sebenarnya berlaku?

Kita boleh melaksanakan arahan berikut untuk melihat proses pemula:

$ go build --ldflags=--dumpdep main.go 2>&1 | grep inittask
Salin selepas log masuk

Hasil output:

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
...
Salin selepas log masuk

Program ini sebenarnya memulakan banyak pakej perisian (perpustakaan standard, pakej pihak ketiga, dll.). Ini menukar saiz pakej daripada 1.3 MB standard kepada 2.3 MB.

Pada skala tertentu, semua orang percaya bahawa impak ini sangat mahal. Kerana anda dapat melihat bahawa program Go dengan hanya 3 baris tidak melakukan apa-apa yang besar.

Program yang sensitif terhadap prestasi permulaan akan menjadi lebih tidak selesa Program biasa juga akan memasuki kitaran ganas dari semasa ke semasa, dan permulaan akan menjadi lebih perlahan daripada biasa.

Penyelesaian

Kami akan melihat penyelesaian bersama-sama dengan cadangan lain "proposal: spec: Go 2: allow manual control over imported package initialization[2]".

Idea terasnya ialah memperkenalkan lazy initialization (lazy init), yang juga sering dipanggil lazy loading dalam industri. Maksudnya, import sebenar dilakukan apabila perlu, dan permulaan selesai apabila pakej tidak diperkenalkan.

Arah pengoptimuman: terutamanya menambahkan pengisytiharan pemula malas selepas mengimport laluan pakej, seperti anotasi go:lazyinit atau go:deferred yang dinyatakan di bawah. Tunggu sehingga program benar-benar digunakan sebelum memulakannya secara rasmi.

1、go:lazyinit 的例子:

package main

import (
      "crypto/x509" // go:lazyinit
      "fmt"
)

func main() {...}
Salin selepas log masuk

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")
        ...
    }
    ...
}
Salin selepas log masuk

以此来实现,可以大大提高启动性能。

讨论

实际上在大多数的社区讨论中,对这个提案是又爱又恨。因为它似乎又有合理的诉求,但细思似乎又会发现完全不对劲。

这个提案的背景和解决方案,是治标不治本的。因为根本原因是:许多库滥用了 init 函数,让许多不必要的东西都初始化了。

Program Go terlalu besar. Bolehkah kita menggunakan pengamulaan malas?

Go 核心开发团队认为让库作者去修复这些库,而不是让 Go 来 “解决” 这些问题。如果支持惰性初始化,也会为这些低质量库的作者提供继续这样做的借口。

似曾相识的感觉

在写这篇文章时,我想起了 Go 的依赖管理(Go modules),其有一个设计是基于语义化版本的规范。

如下图

Program Go terlalu besar. Bolehkah kita menggunakan pengamulaan malas?

版本格式为 “主版本号.次版本号.修订号”,版本号的递增规则如下:

  • 主版本号:当你做了不兼容的 API 修改。
  • 次版本号:当你做了向下兼容的功能性新增。
  • 修订号:当你做了向下兼容的问题修正。

Go modules 的原意是软件库都遵守这个规范,因此内部会有最小版本选择的逻辑。

也就是一个模块往往依赖着许多其它许许多多的模块,并且不同的模块在依赖时很有可能会出现依赖同一个模块的不同版本,Go 会把版本清单都整理出来,最终得到一个构建清单。

如下图:

Program Go terlalu besar. Bolehkah kita menggunakan pengamulaan malas?

Anda akan mendapati bahawa versi pergantungan terakhir yang dibina berkemungkinan tidak konsisten dengan yang dijangkakan, yang membawa kepada banyak masalah perniagaan. Yang paling klasik ialah masalah keserasian berbilang versi grpc-go, protoc-go, etcd, yang membuatkan ramai orang menderita.

Reka bentuk pasukan Go di kawasan ini agak ideal, dan Cao Da juga mengklasifikasikannya sebagai salah satu daripada tujuh dosa maut modul Go. Fungsi init pakej perisian mempunyai banyak masalah dengan permulaan rawak, yang juga agak biasa.

Ringkasan

Penyelesaian (cadangan) untuk masalah ini masih dalam perbincangan.

Bagaimana pula dengan memperkenalkan pemula malas, apa pendapat anda? Selamat tinggalkan mesej dan berbincang di ruangan komen.

Atas ialah kandungan terperinci Program Go terlalu besar. Bolehkah kita menggunakan pengamulaan malas?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:Golang菜鸟
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan