Rumah > pembangunan bahagian belakang > Golang > Tinjauan Di Sebalik Titik Kemasukan Go - Dari Permulaan hingga Keluar

Tinjauan Di Sebalik Titik Kemasukan Go - Dari Permulaan hingga Keluar

Linda Hamilton
Lepaskan: 2024-12-17 22:10:11
asal
835 orang telah melayarinya

A Peek Behind Go’s Entry Point - From Initialization to Exit

Apabila kita mula-mula mula dengan Go, fungsi utama kelihatan hampir terlalu mudah. Satu pintu masuk, main.go terus dan voila - program kami sedang berjalan.

Tetapi apabila kami menggali lebih dalam, saya menyedari terdapat proses halus dan difikirkan dengan baik di sebalik tabir. Sebelum utama bermula, masa jalan Go mengatur permulaan yang teliti bagi semua pakej yang diimport, menjalankan fungsi initnya dan memastikan semuanya berada dalam susunan yang betul - tiada kejutan yang tidak kemas dibenarkan.

Cara Go menyusun mempunyai butiran yang kemas, yang saya rasa setiap pembangun Go harus sedar, kerana ini mempengaruhi cara kami menstruktur kod kami, mengendalikan sumber yang dikongsi dan juga menyampaikan ralat kembali kepada sistem.

Mari kita terokai beberapa senario dan soalan lazim yang menyerlahkan perkara yang sebenarnya berlaku sebelum dan selepas sepakan utama.


Sebelum utama: Permulaan Tertib dan Peranan init

Gambar ini: anda mempunyai berbilang pakej, setiap satu dengan fungsi init mereka sendiri. Mungkin salah satu daripada mereka mengkonfigurasi sambungan pangkalan data, yang lain menetapkan beberapa lalai pengelogan dan yang ketiga memulakan pekerja lambda & yang keempat memulakan pendengar baris gilir SQS.

Menjelang tayangan utama, anda mahu semuanya siap - tiada keadaan separuh dimulakan atau kejutan saat akhir.

Contoh: Pelbagai Pakej dan Pesanan init

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

Apabila anda menjalankan program ini, anda akan melihat:

db: connecting to the database...
cache: warming up the cache...
main: starting main logic now!
Salin selepas log masuk
Salin selepas log masuk

Pangkalan data dimulakan dahulu (sejak mainimport db), kemudian cache dan akhirnya utama mencetak mesejnya. Go menjamin bahawa semua pakej yang diimport dimulakan sebelum mainruns. Pesanan didorong kebergantungan ini adalah kunci. Jika cache bergantung pada db, anda pasti db telah menyelesaikan persediaannya sebelum init cache dijalankan.

Memastikan Perintah Permulaan Khusus

Sekarang, bagaimana jika anda benar-benar memerlukan dbiditial sebelum cache, atau sebaliknya? Pendekatan semula jadi adalah untuk memastikan cache bergantung pada db atau diimport selepas db dalam utama. Go memulakan pakej dalam susunan kebergantungan mereka, bukan susunan import yang disenaraikan dalam main.go. Helah yang kami gunakan ialah import kosong: _ "path/to/package" - untuk memaksa pemulaan pakej tertentu. Tetapi saya tidak akan bergantung pada import kosong sebagai kaedah utama; ia boleh menjadikan kebergantungan kurang jelas dan membawa kepada sakit kepala penyelenggaraan.

Sebaliknya, pertimbangkan untuk menstrukturkan pakej supaya susunan permulaannya muncul secara semula jadi daripada kebergantungan mereka. Jika itu tidak mungkin, mungkin logik pemulaan tidak seharusnya bergantung pada penjujukan yang ketat pada masa penyusunan. Anda boleh, contohnya, membuat semakan cache jika db sedia pada masa jalan, menggunakan penyegerakan. Sekali atau corak yang serupa.

Mengelakkan Kebergantungan Pekeliling

Kebergantungan bulat pada peringkat permulaan adalah tidak boleh dihalang dalam Go. Jika pakej A mengimport B dan B cuba mengimport A, anda baru sahaja mencipta pergantungan bulat . Go akan menolak untuk menyusun, menyelamatkan anda daripada dunia isu masa jalan yang mengelirukan. Ini mungkin terasa ketat, tetapi percayalah, adalah lebih baik untuk mencari masalah ini lebih awal daripada menyahpepijat keadaan permulaan pelik semasa masa jalan.

Berurusan dengan Sumber Dikongsi dan penyegerakan. Sekali

Bayangkan senario di mana pakej A dan B kedua-duanya bergantung pada sumber yang dikongsi - mungkin fail konfigurasi atau objek tetapan global. Kedua-duanya mempunyai fungsi init dan kedua-duanya cuba untuk memulakan sumber itu. Bagaimanakah anda memastikan sumber hanya dimulakan sekali?

Penyelesaian biasa ialah meletakkan pemulaan sumber dikongsi di belakang penyegerakan. Setelah membuat panggilan. Ini memastikan bahawa kod permulaan berjalan tepat sekali, walaupun berbilang pakej mencetuskannya.

Contoh: Memastikan Permulaan Tunggal

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

Kini, tidak kira berapa banyak pakej import konfigurasi, permulaan someValueberlaku sekali sahaja. Jika pakej A dan B kedua-duanya bergantung pada config.Value(), kedua-duanya akan melihat nilai yang dimulakan dengan betul.

Berbilang Fungsi init dalam Satu Fail atau Pakej

Anda boleh mempunyai berbilang fungsi init dalam fail yang sama dan ia akan dijalankan mengikut susunan ia muncul. Merentasi berbilang fail dalam pakej yang sama, Go menjalankan fungsi init dalam susunan yang konsisten tetapi tidak ditakrifkan dengan ketat. Pengkompil mungkin memproses fail dalam susunan abjad, tetapi anda tidak seharusnya bergantung pada itu. Jika kod anda bergantung pada jujukan khusus fungsi init dalam pakej yang sama, itu selalunya tanda untuk memfaktorkan semula. Pastikan logik init minimum dan elakkan gandingan yang ketat.

Penggunaan Sah lwn. Anti-Corak

fungsi init paling baik digunakan untuk persediaan mudah: mendaftar pemacu pangkalan data, memulakan bendera baris arahan atau menyediakan pembalak. Logik yang kompleks, I/O yang berjalan lama atau kod yang mungkin panik tanpa sebab yang kukuh adalah lebih baik dikendalikan di tempat lain.

Sebagai peraturan, jika anda mendapati diri anda menulis banyak logik dalam init, anda mungkin mempertimbangkan untuk membuat logik itu eksplisit dalam utama.

Keluar dengan Rahmat dan Memahami os.Exit()

Materi utama Go tidak mengembalikan nilai. Jika anda ingin memberi isyarat ralat kepada dunia luar, os.Exit() ialah rakan anda. Tetapi perlu diingat: memanggil os.Exit() menamatkan program dengan serta-merta. Tiada fungsi tertunda dijalankan, tiada cetakan kesan tindanan panik.

Contoh: Pembersihan Sebelum Keluar

db: connecting to the database...
cache: warming up the cache...
main: starting main logic now!
Salin selepas log masuk
Salin selepas log masuk

Jika anda melangkau panggilan pembersihan dan melompat terus ke os.Keluar(1), anda kehilangan peluang untuk membersihkan sumber dengan anggun.

Cara Lain untuk Menamatkan Program

Anda juga boleh menamatkan program melalui panik. Panik yang tidak dipulihkan oleh recover() dalam fungsi tertunda akan ranap program dan mencetak surih tindanan. Ini berguna untuk penyahpepijatan tetapi tidak sesuai untuk isyarat ralat biasa. Tidak seperti os.Exit(), panik memberikan fungsi tertunda peluang untuk dijalankan sebelum program tamat, yang boleh membantu dengan pembersihan, tetapi ia juga mungkin kelihatan kurang kemas kepada pengguna akhir atau skrip yang mengharapkan kod keluar yang bersih.

Isyarat (seperti SIGINT dari Cmd C) juga boleh menamatkan program. Jika anda seorang askar, anda boleh menangkap isyarat dan mengendalikannya dengan baik.


Runtime, Concurrency dan Goroutine utama

Permulaan berlaku sebelum sebarang goroutin dilancarkan, memastikan tiada keadaan perlumbaan semasa permulaan. Walau bagaimanapun, sebaik sahaja utama bermula, anda boleh memutarkan seberapa banyak goroutine yang anda suka.

Perlu ambil perhatian bahawa fungsi utama itu sendiri berjalan dalam "goroutine utama" khas yang dimulakan oleh masa jalan Go. Jika main kembali, keseluruhan program akan keluar - walaupun goroutine lain masih berfungsi.

Ini adalah gotcha biasa: hanya kerana anda memulakan gorouti latar belakang tidak bermakna ia mengekalkan program ini. Sebaik sahaja selesai, semuanya ditutup.

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

Dalam contoh ini, goroutine mencetak mesejnya hanya kerana utama menunggu 3 saat sebelum tamat. Jika utama tamat lebih awal, program akan ditamatkan sebelum goroutine selesai. Masa jalan tidak "menunggu" untuk gorout lain apabila keluar utama. Jika logik anda memerlukan menunggu tugasan tertentu selesai, pertimbangkan untuk menggunakan primitif penyegerakan seperti WaitGroup atau saluran untuk memberi isyarat apabila kerja latar belakang selesai.

Bagaimana jika Panik Berlaku Semasa Permulaan?

Jika panik berlaku semasa init, keseluruhan program akan ditamatkan. Tiada utama, tiada peluang pemulihan. Anda akan melihat mesej panik yang boleh membantu anda nyahpepijat. Ini adalah salah satu sebab mengapa saya cuba memastikan fungsi init saya mudah, boleh diramal dan bebas daripada logik kompleks yang mungkin meletup tanpa diduga.


Membungkusnya

Menjelang masa larian utama, Go telah melakukan banyak kerja keras yang tidak kelihatan: ia memulakan semua pakej anda, menjalankan setiap fungsi init dan menyemak bahawa tiada kebergantungan pekeliling yang jahat mengintai. Memahami proses ini memberi anda lebih kawalan dan keyakinan dalam urutan permulaan aplikasi anda.

Apabila berlaku masalah, anda tahu cara keluar dengan bersih dan perkara yang berlaku kepada fungsi tertunda. Apabila kod anda menjadi lebih kompleks, anda tahu cara untuk menguatkuasakan perintah permulaan tanpa menggunakan penggodaman. Dan jika konkurensi berlaku, anda tahu bahawa keadaan perlumbaan bermula selepas larian init, bukan sebelum ini.

Bagi saya, cerapan ini menjadikan fungsi utama Go yang kelihatan mudah kelihatan seperti puncak gunung ais yang elegan. Jika anda mempunyai helah anda sendiri, perangkap yang anda alami, atau soalan tentang dalaman ini, saya ingin mendengarnya.

Lagipun, kita semua masih belajar - dan itulah separuh keseronokan menjadi pembangun Go.


Terima kasih kerana membaca! Semoga kod itu bersama anda :)

Pautan Sosial Saya: LinkedIn | GitHub | ? (dahulunya Twitter) | Substack | Dev.to

Untuk lebih banyak kandungan, sila pertimbangkan untuk mengikuti. Jumpa lagi!

Atas ialah kandungan terperinci Tinjauan Di Sebalik Titik Kemasukan Go - Dari Permulaan hingga Keluar. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
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
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan