Dengan perkembangan pesat Internet, permintaan untuk sistem teragih berskala besar semakin tinggi, dan pengaturcaraan serentak dan pengkomputeran selari telah menjadi kemahiran yang mesti dikuasai oleh pembangun Internet. Bahasa Go ialah bahasa yang dilahirkan untuk menyokong konkurensi Ia berfungsi dengan baik dalam pengaturcaraan serentak dan pengkomputeran selari. Artikel ini akan memperkenalkan mod konkurensi dan pengkomputeran selari bagi bahasa Go dan memberikan beberapa kes praktikal untuk membantu pembaca memahami secara mendalam.
1. Mod konkurensi bahasa Go
Mod konkurensi bahasa Go adalah berdasarkan kepada dua komponen asas goroutine dan saluran. Goroutine ialah benang ringan, diuruskan oleh sistem masa jalan bahasa Go. Ia boleh dimulakan melalui kata kunci go, dan goroutine boleh berkomunikasi melalui saluran.
Berikut ialah contoh mudah goroutine dan saluran:
package main import "fmt" func printMsg(msg string, ch chan string) { ch <- msg } func main() { ch := make(chan string) msgs := []string{"Hello", "Golang", "Parallel"} for _, msg := range msgs { go printMsg(msg, ch) } for i := 0; i < len(msgs); i++ { fmt.Println(<-ch) } }
Kod ini memulakan tiga goroutine melalui gelung for dan masing-masing mengeluarkan tiga rentetan. Fungsi printMsg menulis mesej rentetan ke dalam saluran, dan fungsi utama membaca dari saluran semula.
1.1 Mod Saluran Paip
Dalam bahasa Go, berbilang goroutin boleh disambungkan secara bersiri melalui mod saluran paip untuk membentuk sistem serentak yang lebih kompleks. Pelaksanaan corak saluran paip biasanya melalui komunikasi saluran antara berbilang goroutine, menghantar data dari satu goroutine ke goroutine yang lain, dan memproses dan menukar data dalam setiap goroutine. Berikut ialah contoh mod saluran paip mudah:
package main import ( "fmt" ) func addOne(in <-chan int, out chan<- int) { for val := range in { out <- val + 1 } close(out) } func printNums(out <-chan int) { for val := range out { fmt.Println(val) } } func main() { nums := []int{1, 2, 3} in := make(chan int) out := make(chan int) go addOne(in, out) go printNums(out) for _, num := range nums { in <- num } close(in) }
Kod mentakrifkan 3 goroutine, iaitu goroutine input, ditambah 1 goroutine pemprosesan dan goroutine keluaran Fungsi addOne menambah 1 pada data dalam saluran input dan menulisnya ke saluran output, printNums Fungsi membaca data daripada saluran keluaran dan mengeluarkannya.
1.2 Corak pemilihan
Pernyataan pilih bahasa Go menyediakan cara yang mudah untuk mengendalikan berbilang saluran, iaitu corak pemilihan (corak pilih). Mod pemilihan membolehkan kami melakukan operasi pemilihan tanpa sekatan dalam berbilang saluran Apabila terdapat mesej yang boleh dibaca atau boleh ditulis dalam berbilang saluran, satu akan dipilih secara automatik untuk operasi.
Berikut ialah contoh mod pemilihan mudah:
package main import "fmt" func ping(ch chan<- string) { for { ch <- "ping" } } func pong(ch chan<- string) { for { ch <- "pong" } } func printer(ch <-chan string) { for { fmt.Println(<-ch) } } func main() { ch1 := make(chan string) ch2 := make(chan string) ch3 := make(chan string) go ping(ch1) go pong(ch2) go printer(ch3) for { select { case msg := <-ch1: ch3 <- msg case msg := <-ch2: ch3 <- msg } } }
Dalam kod, fungsi ping dan fungsi pong menghantar mesej "ping" dan "pong" masing-masing ke ch1 dan ch2, dan fungsi pencetak membaca mesej dalam ch3 dan output ia. Dalam fungsi utama, gunakan pernyataan pilih untuk memantau mesej dalam ch1 dan ch2, dan hantar mesej yang diterima ke fungsi pencetak melalui ch3 untuk output.
2. Pengkomputeran selari bahasa Go
Modul pengkomputeran selari terbina dalam bahasa Go termasuk penyegerakan, atom dan konteks, dsb. penyegerakan dan atom terutamanya menggunakan mutex (Mutex) dan operasi atom (operasi atom) untuk mengawal akses data serentak, dan konteks digunakan untuk mengurus maklumat konteks goroutine. Berikut ialah pengenalan ringkas tentang cara menggunakan modul ini:
2.1 Mutex lock
Mutex lock ialah salah satu mekanisme penyegerakan yang paling biasa digunakan untuk melindungi sumber yang dikongsi, dan ia juga merupakan salah satu mekanisme penyegerakan paling asas dalam bahasa Go . Dalam bahasa Go, anda boleh mencipta kunci mutex melalui jenis Mutex dalam pakej penyegerakan. Jenis Mutex menyediakan dua kaedah penting: Kunci dan Buka Kunci. Sebelum mengakses sumber yang dikongsi, anda perlu memanggil kaedah Kunci untuk mendapatkan kunci, dan kemudian memanggil kaedah Buka Kunci untuk melepaskan kunci selepas akses selesai. Berikut ialah contoh kunci mutex mudah:
package main import ( "fmt" "sync" ) func addOne(num *int, mutex *sync.Mutex, wg *sync.WaitGroup) { mutex.Lock() *num += 1 mutex.Unlock() wg.Done() } func main() { var wg sync.WaitGroup var num int mutex := &sync.Mutex{} for i := 0; i < 1000; i++ { wg.Add(1) go addOne(&num, mutex, &wg) } wg.Wait() fmt.Println(num) }
Dalam kod, fungsi addOne ditakrifkan untuk menambah 1 pada pembolehubah num Kunci mutex perlu diperoleh sebelum menambah 1, dan kunci mutex perlu dilepaskan selepas menambah 1. Gunakan WaitGroup untuk menunggu semua gorout menyelesaikan pelaksanaan dan menghasilkan keputusan akhir.
2.2 Operasi atom
Dalam senario konkurensi tinggi, kunci mutex mungkin mengurangkan prestasi program, jadi bahasa Go menyediakan operasi atom untuk menggantikan kunci mutex. Pakej atom menyediakan beberapa fungsi operasi atom, seperti AddInt64, CompareAndSwapInt64, SwapInt64, dsb. Menggunakan operasi atom memastikan bahawa operasi pada pembolehubah tidak akan diganggu oleh goroutine lain dan pelaksanaan serentak tidak akan terjejas. Berikut ialah contoh operasi atom yang mudah:
package main import ( "fmt" "sync/atomic" ) func addOne(num *int64, count *int64, done chan bool) { for i := 0; i < 1000; i++ { atomic.AddInt64(num, 1) } atomic.AddInt64(count, 1) done <- true } func main() { var num int64 var count int64 done := make(chan bool) for i := 0; i < 100; i++ { go addOne(&num, &count, done) } for i := 0; i < 100; i++ { <-done } fmt.Printf("num=%d, count=%d ", num, count) }
Dalam kod, fungsi AddInt64 bagi pakej atom digunakan untuk melaksanakan operasi atom pada pembolehubah num Selepas operasi selesai, utas utama dimaklumkan melalui selesai. Pembolehubah kiraan terkumpul melalui fungsi AddInt64 biasa, dan nilai nombor dan kiraan akhirnya dikeluarkan.
2.3 Pengurusan Konteks
Dalam bahasa Go, selalunya perlu untuk menghantar maklumat konteks antara berbilang goroutin, seperti ID permintaan, tetapan tamat masa, dsb. Pakej konteks menyediakan cara yang mudah untuk mengurus maklumat konteks goroutine. Apabila menggunakan konteks, anda biasanya perlu mencipta konteks induk dalam goroutine utama Apabila memperoleh goroutine, gunakan WithCancel, WithDeadline, WithValue dan fungsi lain untuk mencipta konteks kanak-kanak dan menyampaikan maklumat konteks yang sepadan. Berikut ialah contoh pengurusan konteks mudah:
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("worker %d canceled ", id) return default: fmt.Printf("worker %d is working ", id) time.Sleep(1 * time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) for i := 0; i < 3; i++ { go worker(ctx, i) } time.Sleep(5 * time.Second) cancel() }
Dalam kod, gunakan pakej konteks untuk mencipta konteks induk dan cipta konteks kanak-kanak melalui fungsi WithCancel. Dalam fungsi pekerja, gunakan pernyataan pilih untuk mendengar isyarat ctx.Done() Apabila ctx.Done() ditutup, ini bermakna konteks dibatalkan dan fungsi pekerja perlu keluar. Dalam fungsi utama, tutup subkonteks melalui fungsi batal dan tunggu subkonteks dibatalkan. Keputusan yang dijalankan adalah seperti berikut:
worker 0 is working worker 1 is working worker 2 is working worker 2 canceled worker 1 canceled worker 0 canceled
Apabila konteks induk dibatalkan, semua konteks kanak-kanak akan menerima pemberitahuan dan keluar dari pelaksanaan.
3. Kesimpulan
Artikel ini memperkenalkan secara ringkas mod konkurensi dan pengkomputeran selari bahasa Go, dan memperkenalkan komponen dan modul asas seperti goroutine, saluran, kunci mutex, operasi atom dan konteks. Dengan mempelajari pengetahuan asas ini, kita boleh menguasai pengaturcaraan serentak dan selari bahasa Go dengan lebih baik, dan meletakkan asas untuk membina aplikasi Internet berprestasi tinggi dan berkonkurensi tinggi.
Atas ialah kandungan terperinci Kuasai mod konkurensi dan pengkomputeran selari bahasa Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!