Go를 처음 시작하면 주요 기능이 너무 단순해 보일 정도입니다. 단일 진입점, 간단하게 main.go 실행 및 짜잔 - 우리 프로그램이 실행 중입니다.
하지만 더 깊이 파고들면서 커튼 뒤에는 미묘하고 세심하게 계획된 과정이 있다는 것을 깨달았습니다. 메인이 시작되기 전에 Go 런타임은 가져온 모든 패키지의 초기화를 신중하게 조정하고 초기화 기능을 실행하며 모든 것이 올바른 순서로 되어 있는지 확인합니다. 혼란스러운 상황은 허용되지 않습니다.
Go가 정렬하는 방식에는 모든 Go 개발자가 알아야 할 깔끔한 세부 사항이 있습니다. 이는 코드 구조화, 공유 리소스 처리, 심지어 오류를 시스템에 다시 전달하는 방식에 영향을 미치기 때문입니다.
메인 킥이 시작되기 전과 후에 실제로 무슨 일이 일어나고 있는지 강조하는 몇 가지 일반적인 시나리오와 질문을 살펴보겠습니다.
메인 이전: 순차적 초기화 및 init의 역할
이렇게 생각해 보세요. 각각 고유한 초기화 기능이 있는 여러 패키지가 있습니다. 그 중 하나는 데이터베이스 연결을 구성하고, 다른 하나는 일부 로깅 기본값을 설정하고, 세 번째는 람다 작업자를 초기화하고, 네 번째는 SQS 대기열 수신기를 초기화할 수 있습니다.
메인 실행 시간에는 모든 것이 준비되어 있어야 합니다. 절반 초기화된 상태나 마지막 순간의 놀라움은 없어야 합니다.
예: 여러 패키지 및 주문 초기화
// db.go package db import "fmt" func init() { fmt.Println("db: connecting to the database...") // Imagine a real connection here } // cache.go package cache import "fmt" func init() { fmt.Println("cache: warming up the cache...") // Imagine setting up a cache here } // main.go package main import ( _ "app/db" // blank import for side effects _ "app/cache" "fmt" ) func main() { fmt.Println("main: starting main logic now!") }
이 프로그램을 실행하면 다음이 표시됩니다.
db: connecting to the database... cache: warming up the cache... main: starting main logic now!
데이터베이스가 먼저 초기화되고(mainimports db 이후) 캐시가 마지막으로 메시지를 인쇄합니다. Go는 가져온 모든 패키지가 메인 실행 전에 초기화되도록 보장합니다. 이 종속성 기반 순서가 핵심입니다. 캐시가 db에 의존하는 경우 캐시 초기화가 실행되기 전에 db가 설정을 완료했을 것입니다.
특정 초기화 순서 보장
이제 캐시 전에 반드시 dinitialized가 필요하거나 그 반대의 경우에는 어떻게 될까요? 자연스러운 접근 방식은 캐시가 db에 의존하는지 확인하거나 기본에서 db 이후에 가져오는 것입니다. Go는 main.go에 나열된 가져오기 순서가 아닌 종속성 순서대로 패키지를 초기화합니다. 우리가 사용하는 트릭은 빈 가져오기입니다: _ "path/to/package" - 특정 패키지를 강제로 초기화합니다. 하지만 나는 빈 가져오기를 기본 방법으로 사용하지 않을 것입니다. 종속성이 덜 명확해지고 유지 관리 문제가 발생할 수 있습니다.
대신 초기화 순서가 종속성에 따라 자연스럽게 나타나도록 패키지를 구성하는 것이 좋습니다. 이것이 가능하지 않다면 초기화 논리가 컴파일 시 엄격한 순서에 의존해서는 안 됩니다. 예를 들어 sync.Once 또는 유사한 패턴을 사용하여 런타임 시 db가 준비되었는지 캐시 검사를 수행할 수 있습니다.
순환 종속성 방지
초기화 수준의 순환 종속성은 Go에서 절대 금기 사항입니다. 패키지 A가 B를 가져오고 B가 A를 가져오려고 하면 순환 종속성이 생성된 것입니다. . Go는 컴파일을 거부하여 혼란스러운 런타임 문제의 세계에서 여러분을 구해줍니다. 엄격하게 느껴질 수도 있지만 저를 믿으세요. 런타임에 이상한 초기화 상태를 디버깅하는 것보다 이러한 문제를 조기에 발견하는 것이 더 좋습니다.
공유 리소스 및 sync.Once 처리
A 및 B 패키지가 모두 공유 리소스(예: 구성 파일 또는 전역 설정 개체)에 의존하는 시나리오를 상상해 보세요. 둘 다 initfunctions를 갖고 있으며 둘 다 해당 리소스를 초기화하려고 시도합니다. 리소스가 한 번만 초기화되도록 어떻게 보장하나요?
일반적인 해결책은 sync.Once 호출 뒤에 공유 리소스 초기화를 배치하는 것입니다. 이렇게 하면 여러 패키지가 이를 트리거하더라도 초기화 코드가 정확히 한 번만 실행됩니다.
예: 단일 초기화 보장
// db.go package db import "fmt" func init() { fmt.Println("db: connecting to the database...") // Imagine a real connection here } // cache.go package cache import "fmt" func init() { fmt.Println("cache: warming up the cache...") // Imagine setting up a cache here } // main.go package main import ( _ "app/db" // blank import for side effects _ "app/cache" "fmt" ) func main() { fmt.Println("main: starting main logic now!") }
이제 가져오기 구성의 패키지 수에 관계없이 someValue의 초기화는 한 번만 발생합니다. 패키지 A와 B가 모두 config.Value()에 의존하는 경우 둘 다 적절하게 초기화된 값을 볼 수 있습니다.
단일 파일 또는 패키지의 여러 초기화 함수
동일한 파일에 여러 개의 init 함수가 있을 수 있으며 표시된 순서대로 실행됩니다. 동일한 패키지의 여러 파일에서 Go는 일관되지만 엄격하게 정의되지 않은 순서로 init 함수를 실행합니다. 컴파일러는 파일을 알파벳순으로 처리할 수 있지만 이에 의존해서는 안 됩니다. 코드가 동일한 패키지 내의 특정 init 함수 시퀀스에 의존하는 경우 이는 종종 리팩토링하라는 신호입니다. 초기화 논리를 최소화하고 긴밀한 결합을 피하세요.
적법한 사용과 안티 패턴
init 함수는 간단한 설정(데이터베이스 드라이버 등록, 명령줄 플래그 초기화 또는 로거 설정)에 가장 적합합니다. 복잡한 논리, 장기간 실행되는 I/O 또는 합당한 이유 없이 패닉이 발생할 수 있는 코드는 다른 곳에서 더 잘 처리됩니다.
경험상, init에 많은 로직을 작성하고 있다면 해당 로직을 main에서 명시적으로 만드는 것을 고려해 볼 수 있습니다.
은혜롭게 종료하고 os.Exit() 이해하기
Go의 메인은 값을 반환하지 않습니다. 외부 세계에 오류를 알리고 싶다면 os.Exit()가 도움이 됩니다. 하지만 명심하세요: os.Exit()를 호출하면 프로그램이 즉시 종료됩니다. 지연된 기능이 실행되지 않으며 패닉 스택 추적이 인쇄되지 않습니다.
예: 퇴실 전 정리
db: connecting to the database... cache: warming up the cache... main: starting main logic now!
정리 호출을 건너뛰고 바로 os.Exit(1)으로 점프하면 리소스를 적절하게 정리할 기회를 잃게 됩니다.
프로그램을 종료하는 다른 방법
패닉 상태로 인해 프로그램이 종료될 수도 있습니다. 지연된 함수에서 Recover()에 의해 복구되지 않은 패닉은 프로그램을 중단시키고 스택 추적을 인쇄합니다. 이는 디버깅에 편리하지만 일반적인 오류 신호에는 적합하지 않습니다. os.Exit()와 달리 패닉은 프로그램이 끝나기 전에 지연된 함수를 실행할 수 있는 기회를 제공하여 정리에 도움이 될 수 있지만 깨끗한 종료 코드를 기대하는 최종 사용자나 스크립트에게는 덜 깔끔해 보일 수도 있습니다.
Cmd C의 SIGINT와 같은 신호도 프로그램을 종료할 수 있습니다. 군인이라면 신호를 잡아서 우아하게 처리할 수 있습니다.
런타임, 동시성 및 주요 고루틴
고루틴이 시작되기 전에 초기화가 이루어지므로 시작 시 경쟁 조건이 발생하지 않습니다. 그러나 메인이 시작되면 원하는 만큼 고루틴을 실행할 수 있습니다.
main 함수 자체는 Go 런타임에 의해 시작된 특별한 "메인 고루틴"에서 실행된다는 점에 유의하는 것이 중요합니다. main이 반환되면, 다른 고루틴이 여전히 작업을 수행 중이더라도 전체 프로그램이 종료됩니다.
이것은 일반적인 문제입니다. 백그라운드 고루틴을 시작했다고 해서 프로그램이 계속 활성 상태로 유지되는 것은 아닙니다. 메인이 끝나면 모든 것이 종료됩니다.
// db.go package db import "fmt" func init() { fmt.Println("db: connecting to the database...") // Imagine a real connection here } // cache.go package cache import "fmt" func init() { fmt.Println("cache: warming up the cache...") // Imagine setting up a cache here } // main.go package main import ( _ "app/db" // blank import for side effects _ "app/cache" "fmt" ) func main() { fmt.Println("main: starting main logic now!") }
이 예에서 고루틴은 메인이 종료되기 전에 3초를 기다리기 때문에 메시지만 인쇄합니다. 메인이 더 빨리 종료되면 프로그램은 고루틴이 완료되기 전에 종료됩니다. 런타임은 메인이 종료될 때 다른 고루틴을 "기다리지" 않습니다. 논리에서 특정 작업이 완료될 때까지 기다려야 하는 경우 WaitGroup 또는 채널과 같은 동기화 프리미티브를 사용하여 백그라운드 작업이 완료될 때 신호를 보내는 것을 고려해 보세요.
초기화 중에 패닉이 발생하면 어떻게 되나요?
초기화 중에 패닉이 발생하면 전체 프로그램이 종료됩니다. 메인도 없고 회복 기회도 없습니다. 디버깅에 도움이 되는 패닉 메시지가 표시됩니다. 이것이 제가 초기화 함수를 단순하고 예측 가능하게 유지하고 예기치 않게 폭발할 수 있는 복잡한 논리가 없도록 노력하는 이유 중 하나입니다.
마무리
메인이 실행될 때까지 Go는 이미 눈에 보이지 않는 수많은 발품 작업을 수행했습니다. 모든 패키지를 초기화하고 모든 init 함수를 실행하며 주변에 숨어 있는 불쾌한 순환 종속성이 없는지 확인했습니다. 이 프로세스를 이해하면 애플리케이션의 시작 순서를 더 잘 제어하고 확신할 수 있습니다.
뭔가 문제가 발생하면 깔끔하게 종료하는 방법과 지연된 함수에 어떤 일이 발생하는지 알 수 있습니다. 코드가 더욱 복잡해지면 해킹에 의존하지 않고 초기화 순서를 적용하는 방법을 알게 됩니다. 그리고 동시성이 발생하면 경쟁 조건은 init 실행 전이 아니라 실행 후에 시작된다는 것을 알 수 있습니다.
저에게는 이러한 통찰력으로 인해 단순해 보이는 Go의 주요 기능이 우아한 빙산의 일각처럼 느껴졌습니다. 여러분만의 비법이나, 우연히 부딪힌 함정이 있거나, 이러한 내부 요소에 대한 질문이 있다면 듣고 싶습니다.
결국 우리 모두는 아직 배우는 중입니다. 그게 Go 개발자가 되는 재미의 절반입니다.
읽어주셔서 감사합니다! 코드가 함께하길 바랍니다 :)
내 소셜 링크: LinkedIn | GitHub | ? (이전 트위터) | 서브스택 | Dev.to
더 많은 콘텐츠를 보려면 다음을 고려하세요. 또 봐요!
위 내용은 Go의 진입점 뒤편 살펴보기 - 초기화부터 종료까지의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

GO의 문자열 패키지는 다양한 문자열 조작 기능을 제공합니다. 1) 문자열을 사용하여 기판을 확인하십시오. 2) strings.split을 사용하여 문자열을 서브 스트링 슬라이스로 분할하십시오. 3) 문자열을 통해 문자열을 병합합니다. 4) 문자열의 시작과 끝에서 strings.trimspace 또는 strings.trim을 사용하여 공백 또는 지정된 문자를 제거하십시오. 5) 지정된 모든 하위 문구를 문자열로 교체하십시오. 6) strings.hasprefix 또는 strings.hassuffix를 사용하여 문자열의 접두사 또는 접미사를 확인하십시오.

Go Language Strings 패키지를 사용하면 코드 품질이 향상 될 수 있습니다. 1) strings.join ()을 사용하여 성능 오버 헤드를 피하기 위해 문자열 배열을 우아하게 연결하십시오. 2) strings.split () 및 strings.contains ()를 결합하여 텍스트를 처리하고 사례 민감도 문제에주의를 기울입니다. 3) 문자열의 남용을 피하고 ()을 replace ()하고 많은 수의 대체에 정규 표현식을 사용하는 것을 고려하십시오. 4) strings.builder를 사용하여 자주 스 플라이 싱 스트링의 성능을 향상시킵니다.

GO의 바이트 패키지는 바이트 슬라이싱을 처리하기위한 다양한 실용적인 기능을 제공합니다. 1. BYTES는 바이트 슬라이스에 특정 시퀀스가 포함되어 있는지 확인하는 데 사용됩니다. 2.Bytes.split은 바이트 슬라이스를 작은 피스로 분할하는 데 사용됩니다. 3.Bytes.join은 여러 바이트 슬라이스를 하나로 연결하는 데 사용됩니다. 4.bytes.trimspace는 바이트 슬라이스의 전면 및 후면 블랭크를 제거하는 데 사용됩니다. 5.Bytes.equal은 두 바이트 슬라이스가 동일인지 비교하는 데 사용됩니다. 6.bytes.index는 LargersLices에서 하위 슬라이스의 시작 지수를 찾는 데 사용됩니다.

Theencoding/BinaryPackageInsentialBecauseItProvideAstandAdizedWayStandwriteBinaryData, Cross-PlatformCompatibility 및 HandshandlingDifferentendianness.ItoffersFunctionsLikeRead, Write, andwriteUvarIntForPrecisControloverbinary

thebackageoiscrucialforhandlingbyteslicesandbuffers, ontowtoolsforefficiledmemorymanagementanddatamanipulation.1) itprovideFunctionItieslikeCreatingBuffers, 비교 및 교체/교체, 2) forlargedatasets, 사용

텍스트 데이터를 처리하는 도구를 제공하고 기본 문자열에서 고급 정규 표현식에 이르기까지 텍스트 데이터를 처리 할 수있는 도구를 제공하기 때문에 이동 중 "문자열"패키지에주의해야합니다. 1) "Strings"패키지는 성능 문제를 피하기 위해 문자열을 스플 라이스하는 데 사용되는 결합 기능과 같은 효율적인 스트링 작업을 제공합니다. 2) 포함 함수와 같은 고급 함수가 포함되어있어 문자열에 특정 문자 세트가 포함되어 있는지 확인합니다. 3) 교체 함수는 문자열의 하위 문자열을 대체하는 데 사용되며 교체 순서 및 사례 감도에주의를 기울여야합니다. 4) 분할 함수는 분리기에 따라 문자열을 분할 할 수 있으며 종종 정규 발현 처리에 사용됩니다. 5) 사용 할 때 성능을 고려해야합니다.

"인코딩/바이너리"패키지 인테이블 링 베이너리 데이터, 1) ItsupportsBothlittle-endianandbig-endianByteorders, CruialCross-SystemCompatibility .2) ThePackagealLowworkingwithcus

바이트 패키지를 GO에서 마스터하면 코드의 효율성과 우아함을 향상시키는 데 도움이 될 수 있습니다. 1) 바이트 패키지는 이진 데이터를 구문 분석, 네트워크 프로토콜 및 메모리 관리에 중요합니다. 2) BYTES.BUFFER를 사용하여 점차적으로 바이트 슬라이스를 작성하십시오. 3) 바이트 패키지는 바이트 슬라이스 검색, 교체 및 세분화 기능을 제공합니다. 4) BYTES.READER 유형은 특히 I/O 작업에서 바이트 슬라이스의 데이터를 읽는 데 적합합니다. 5) Bytes 패키지는 GO의 가비지 수집기와 협력하여 빅 데이터 처리의 효율성을 향상시킵니다.


핫 AI 도구

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

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

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

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

SublimeText3 영어 버전
권장 사항: Win 버전, 코드 프롬프트 지원!

SecList
SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

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

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

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)