Rumah >pembangunan bahagian belakang >Golang >Menguasai Go&#s Concurrency: Tingkatkan Kod Anda dengan Goroutine dan Saluran

Menguasai Go&#s Concurrency: Tingkatkan Kod Anda dengan Goroutine dan Saluran

Susan Sarandon
Susan Sarandonasal
2024-12-24 19:29:20907semak imbas

Mastering Go

Gorutin dan saluran ialah tulang belakang model konkurensi Go. Ia bukan hanya alat mudah; ia adalah binaan berkuasa yang membolehkan kami membina sistem yang kompleks dan berprestasi tinggi.

Mari kita mulakan dengan goroutine. Ia seperti benang ringan, tetapi lebih cekap. Kita boleh melahirkan beribu-ribu daripada mereka tanpa mengeluarkan peluh. Berikut ialah contoh asas:

func main() {
    go func() {
        fmt.Println("Hello from a goroutine!")
    }()
    time.Sleep(time.Second)
}

Tetapi itu hanya menconteng permukaan. Keajaiban sebenar berlaku apabila kita menggabungkan goroutine dengan saluran.

Saluran adalah seperti paip yang menyambungkan goroutin. Mereka membenarkan kami menghantar dan menerima nilai antara bahagian serentak program kami. Berikut ialah contoh mudah:

func main() {
    ch := make(chan string)
    go func() {
        ch <- "Hello, channel!"
    }()
    msg := <-ch
    fmt.Println(msg)
}

Sekarang, mari kita selami beberapa corak lanjutan. Salah satu kegemaran saya ialah kolam pekerja. Ia ialah sekumpulan gorout yang memproses tugasan daripada baris gilir yang dikongsi. Begini cara kami boleh melaksanakannya:

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Printf("Worker %d processing job %d\n", id, j)
        time.Sleep(time.Second)
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)

    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    for j := 1; j <= 9; j++ {
        jobs <- j
    }
    close(jobs)

    for a := 1; a <= 9; a++ {
        <-results
    }
}

Corak ini bagus untuk mengagihkan kerja merentasi berbilang pemproses. Ia berskala dan cekap.

Satu lagi corak berkuasa ialah sistem pub-sub. Ia sesuai untuk menyiarkan mesej kepada berbilang penerima. Berikut ialah pelaksanaan asas:

type Subscription struct {
    ch chan interface{}
}

type PubSub struct {
    mu   sync.RWMutex
    subs map[string][]Subscription
}

func (ps *PubSub) Subscribe(topic string) Subscription {
    ps.mu.Lock()
    defer ps.mu.Unlock()

    sub := Subscription{ch: make(chan interface{}, 1)}
    ps.subs[topic] = append(ps.subs[topic], sub)
    return sub
}

func (ps *PubSub) Publish(topic string, msg interface{}) {
    ps.mu.RLock()
    defer ps.mu.RUnlock()

    for _, sub := range ps.subs[topic] {
        select {
        case sub.ch <- msg:
        default:
        }
    }
}

Sistem ini membenarkan berbilang gorout melanggan topik dan menerima mesej secara tidak segerak.

Sekarang, mari kita bincangkan tentang penyataan pilihan. Ia seperti suis untuk saluran, membenarkan kami mengendalikan berbilang operasi saluran. Kita juga boleh menambah tamat masa:

select {
case msg1 := <-ch1:
    fmt.Println("Received", msg1)
case msg2 := <-ch2:
    fmt.Println("Received", msg2)
case <-time.After(time.Second):
    fmt.Println("Timed out")
}

Corak ini penting untuk mengendalikan berbilang operasi serentak tanpa menyekat.

Semaphore adalah satu lagi konsep penting. Kami boleh melaksanakannya menggunakan saluran penimbal:

type Semaphore chan struct{}

func (s Semaphore) Acquire() {
    s <- struct{}{}
}

func (s Semaphore) Release() {
    <-s
}

func main() {
    sem := make(Semaphore, 3)
    for i := 0; i < 5; i++ {
        go func(id int) {
            sem.Acquire()
            defer sem.Release()
            fmt.Printf("Worker %d is working\n", id)
            time.Sleep(time.Second)
        }(i)
    }
    time.Sleep(3 * time.Second)
}

Corak ini membolehkan kami mengehadkan akses serentak kepada sumber.

Mari beralih kepada penutupan yang anggun. Ia penting untuk perkhidmatan yang berjalan lama. Berikut ialah corak yang sering saya gunakan:

func main() {
    stop := make(chan struct{})
    go func() {
        sigint := make(chan os.Signal, 1)
        signal.Notify(sigint, os.Interrupt)
        <-sigint
        close(stop)
    }()

    for {
        select {
        case <-stop:
            fmt.Println("Shutting down...")
            return
        default:
            // Do work
        }
    }
}

Ini memastikan program kami boleh ditutup dengan bersih apabila ia menerima isyarat gangguan.

Tekanan belakang adalah satu lagi konsep penting dalam sistem serentak. Ini mengenai mengurus aliran data apabila pengeluar mengatasi pengguna. Berikut ialah contoh mudah menggunakan saluran penimbal:

func producer(ch chan<- int) {
    for i := 0; ; i++ {
        ch <- i
    }
}

func consumer(ch <-chan int) {
    for v := range ch {
        fmt.Println(v)
        time.Sleep(time.Second)
    }
}

func main() {
    ch := make(chan int, 10)
    go producer(ch)
    consumer(ch)
}

Penimbal dalam saluran bertindak sebagai penyerap hentak, membolehkan pengeluar meneruskan walaupun pengguna lambat buat sementara waktu.

Sekarang, mari kita bincangkan tentang masa jalanan Go. Ia bertanggungjawab untuk menjadualkan gorout ke rangkaian OS. Kita boleh mempengaruhi ini dengan pembolehubah persekitaran GOMAXPROCS, tetapi biasanya, lalai adalah yang terbaik.

Kami juga boleh menggunakan runtime.NumGoroutine() untuk melihat bilangan goroutine sedang berjalan:

fmt.Println(runtime.NumGoroutine())

Ini boleh berguna untuk nyahpepijat dan pemantauan.

Mengoptimumkan kod serentak ialah satu seni. Satu prinsip utama adalah untuk memastikan goroutine berumur pendek. Goroutine yang berjalan lama boleh memburu sumber. Sebaliknya, gunakan kumpulan pekerja untuk tugasan yang berpanjangan.

Petua lain: gunakan saluran penimbal apabila anda mengetahui bilangan nilai yang akan anda hantar. Mereka boleh meningkatkan prestasi dengan mengurangkan penyegerakan.

Mari kita akhiri dengan contoh yang kompleks: pemproses tugas teragih. Ini menggabungkan banyak corak yang telah kami bincangkan:

func main() {
    go func() {
        fmt.Println("Hello from a goroutine!")
    }()
    time.Sleep(time.Second)
}

Sistem ini mengagihkan tugas merentasi berbilang pekerja, memprosesnya secara serentak dan mengumpul hasilnya.

Kesimpulannya, primitif konkurensi Go ialah alat yang berkuasa. Mereka membenarkan kami membina sistem yang kompleks dan berprestasi tinggi dengan relatif mudah. Tetapi dengan kuasa yang besar datang tanggungjawab yang besar. Adalah penting untuk memahami corak ini secara mendalam untuk mengelakkan perangkap biasa seperti kebuntuan dan keadaan perlumbaan.

Ingat, konkurensi bukan selalu jawapannya. Kadangkala, kod jujukan mudah adalah lebih jelas dan pantas. Sentiasa profilkan kod anda untuk memastikan konkurensi sebenarnya meningkatkan prestasi.

Akhir sekali, teruskan belajar. Komuniti Go sentiasa membangunkan corak baharu dan amalan terbaik. Kekal ingin tahu, mencuba dan berkongsi penemuan anda. Begitulah cara kita semua berkembang sebagai pembangun.


Ciptaan Kami

Pastikan anda melihat ciptaan kami:

Pusat Pelabur | Hidup Pintar | Epos & Gema | Misteri Membingungkan | Hindutva | Pembangunan Elit | Sekolah JS


Kami berada di Medium

Tech Koala Insights | Dunia Epok & Gema | Medium Pusat Pelabur | Medium Misteri Membingungkan | Sains & Zaman Sederhana | Hindutva Moden

Atas ialah kandungan terperinci Menguasai Go&#s Concurrency: Tingkatkan Kod Anda dengan Goroutine dan Saluran. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
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