Go 프로그램이 너무 큽니다. 지연 초기화를 사용할 수 있나요?
회사의 지속적인 발전 속에서 대부분이 초기에는 대형 유닛이었고 변화도 느렸습니다. 창고는 10년 이상 사용할 예정이며 창고 규모는 기본적으로 지속적으로 증가하는 과정.
영향 중 하나는 패키징된 애플리케이션의 크기가 점점 커지고, 어디에 사용되는지 알 수 없다는 점인데... 오늘 논의할 제안은 "제안: 언어: 지연 초기화 가져오기 가능 부작용 없이 수입 [1]'이 이와 관련이 있습니다.
Proposal
Background
아주 간단한 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 ...
이 프로그램은 실제로 많은 소프트웨어 패키지(표준 라이브러리, 타사 패키지 등)를 초기화합니다. 이로 인해 패키지 크기가 표준 1.3MB에서 2.3MB로 변경됩니다.
특정 규모에서 모든 사람은 이러한 영향이 매우 비싸다고 믿습니다. 3줄 Go 프로그램은 실질적인 작업을 수행하지 않는다는 것을 알 수 있기 때문입니다.
시작 성능에 민감한 프로그램은 더욱 불편해집니다. 일반 프로그램도 시간이 지남에 따라 악순환에 빠지고 시작이 평소보다 느려집니다.
솔루션
다른 제안 "제안: 사양: Go 2: 가져온 패키지 초기화에 대한 수동 제어 허용[2]"과 함께 솔루션을 살펴보겠습니다.
핵심 아이디어는 업계에서 지연 로딩이라고도 불리는 지연 초기화(lazy init)를 도입하는 것입니다. 즉, 필요한 경우 실제 import가 이루어지고, 패키지가 도입되지 않은 경우에는 초기화가 완료됩니다.
최적화 방향: 아래에 언급된 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의 다중 버전 호환성 문제로 많은 사람들이 어려움을 겪고 있습니다.
이 분야에서 Go 팀의 디자인은 비교적 이상적이며 Cao Da도 이를 Go 모듈의 일곱 가지 대죄 중 하나로 분류했습니다. 소프트웨어 패키지의 init 기능은 무작위 초기화에 문제가 많은데, 이 역시 조금은 익숙합니다.
요약
이 문제에 대한 해결책(제안)은 아직 논의 중입니다. 분명히 Go 팀은 소프트웨어 라이브러리 작성자가 자신의 코드를 제한하고 무작위로 초기화하지 않기를 바랍니다.
지연 초기화를 도입하는 것은 어떻습니까? 댓글 영역에서 메시지를 남기고 토론하는 것을 환영합니다.
위 내용은 Go 프로그램이 너무 큽니다. 지연 초기화를 사용할 수 있나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

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 코루틴을 사용하면 메모리 누수를 방지하기 위해 종료 시 코루틴 스택 메모리가 자동으로 해제됩니다.

IDE를 사용하여 Go 함수 문서 보기: 함수 이름 위에 커서를 놓습니다. 단축키(GoLand: Ctrl+Q, VSCode: GoExtensionPack 설치 후 F1을 누르고 "Go:ShowDocumentation" 선택)를 누릅니다.

Golang에서 오류 래퍼를 사용하면 원래 오류에 상황별 정보를 추가하여 새로운 오류를 생성할 수 있습니다. 이는 다양한 라이브러리나 구성 요소에서 발생하는 오류 유형을 통합하여 디버깅 및 오류 처리를 단순화하는 데 사용할 수 있습니다. 단계는 다음과 같습니다. error.Wrap 함수를 사용하여 원래 오류를 새 오류로 래핑합니다. 새 오류에는 원래 오류의 상황별 정보가 포함됩니다. fmt.Printf를 사용하면 래핑된 오류를 출력하여 더 많은 컨텍스트와 실행 가능성을 제공할 수 있습니다. 다양한 유형의 오류를 처리할 때 오류 유형을 통합하려면 오류.Wrap 함수를 사용하세요.

단위 테스트 동시 기능은 동시 환경에서 올바른 동작을 보장하는 데 도움이 되므로 매우 중요합니다. 동시 기능을 테스트할 때는 상호 배제, 동기화, 격리와 같은 기본 원칙을 고려해야 합니다. 동시 기능은 경쟁 조건을 시뮬레이션하고, 테스트하고, 결과를 확인하여 단위 테스트할 수 있습니다.
