Saluran (saluran) tak segerak ialah salah satu ciri yang sangat penting dalam bahasa Go, yang membolehkan kami berkomunikasi dan menyegerakkan antara goroutin. Kaedah komunikasi ini sangat cekap dan lebih selamat daripada memori kongsi kerana operasi baca/tulis pada memori kongsi memerlukan penguncian eksplisit untuk mengelakkan keadaan perlumbaan. Dalam artikel ini, kita akan membincangkan beberapa teknik biasa yang digunakan dalam pengendalian saluran tak segerak.
Saluran buffered ialah saluran tak segerak yang boleh menampan beberapa elemen tertentu antara operasi penghantaran dan penerimaan, supaya Pihak tidak perlu menunggu pihak yang menerima. Dalam erti kata lain, saluran penimbal membenarkan coroutine berkomunikasi secara tidak segerak.
Sebagai contoh, berikut ialah contoh penggunaan saluran penimbal:
package main import "fmt" func main() { ch := make(chan int, 2) // 创建缓冲信道,缓存两个元素 ch <- 1 ch <- 2 fmt.Println(<-ch) // 从信道中读取第一个元素 fmt.Println(<-ch) // 从信道中读取第二个元素 }
Outputnya ialah:
1 2
Dalam contoh di atas, kami mencipta saluran penimbalch
, cache dua elemen integer. Kemudian kami menggunakan dua pernyataan ch <- 1
dan ch <- 2
untuk menghantar dua elemen ke saluran. Akhir sekali, kami menggunakan <-ch
untuk membaca dua elemen daripada saluran dua kali.
Perlu diingatkan bahawa jika kita cuba menghantar elemen ke saluran penimbal yang sudah penuh, operasi hantar akan menyekat sehingga terdapat kedudukan bebas dalam saluran. Begitu juga, jika kita cuba membaca elemen daripada saluran buffer kosong, operasi baca juga akan menyekat sehingga terdapat elemen dalam saluran.
Apabila menggunakan saluran tak segerak, kita mesti memberi perhatian kepada beberapa butiran. Sebagai contoh, apakah yang berlaku apabila kita membaca data daripada saluran tertutup?
Apabila kami cuba membaca data daripada saluran tertutup, operasi baca tidak lagi akan menyekat, tetapi akan segera mengembalikan nilai sifar. Sebagai contoh, dalam contoh berikut kita dapat melihat bahawa apabila kita membaca elemen dari saluran tertutup, nilai sifar jenis akan dikembalikan:
package main import "fmt" func main() { ch := make(chan int) close(ch) // 关闭信道 x, ok := <-ch // 读取信道 fmt.Println(x, ok) // 输出:0 false }
Perlu diingatkan bahawa kita perlu memastikan bahawa terdapat Hanya tutup saluran apabila coroutine menggunakannya. Jika hanya satu coroutine yang menggunakan saluran, maka kami tidak perlu menutup saluran secara manual, kerana ini boleh menyebabkan coroutine lain panik apabila cuba menghantar data ke saluran ini.
Dalam sesetengah kes, kami mungkin menghadapi masalah tamat masa semasa menunggu data daripada saluran. Contohnya, apabila kami membaca data daripada sambungan rangkaian, jika masa ketibaan data melebihi masa menunggu yang kami tetapkan, maka kami perlu menutup sambungan supaya coroutine lain boleh menggunakan sumber ini.
Dalam pemprosesan saluran tak segerak, kita boleh menggunakan pernyataan select
untuk menyesuaikan mekanisme tamat masa. Berikut ialah contoh menggunakan pernyataan select
untuk melaksanakan mekanisme tamat masa saluran:
package main import ( "fmt" "time" ) func main() { ch := make(chan int) go func() { time.Sleep(5 * time.Second) ch <- 1 }() select { case x := <-ch: fmt.Println(x) case <-time.After(3 * time.Second): fmt.Println("timeout!") } }
Dalam contoh di atas, kami menggunakan fungsi time.After()
untuk mengembalikan contoh jenis time.Timer
untuk menunggu tamat masa. Jika saluran menerima data sebelum tamat masa, kami boleh mendapatkan data daripada pernyataan x := <-ch
. Jika tidak, apabila tamat masa berlaku, pernyataan <-time.After(3 * time.Second)
akan dilaksanakan serta-merta dan maklumat berkaitan tamat masa akan dikeluarkan.
Perlu diingatkan bahawa apabila menggunakan mekanisme tamat masa saluran, kita juga harus memberi perhatian kepada saluran mana yang ditutup untuk mengelakkan panik sementara menunggu saluran menerima data.
select
pernyataan ialah struktur bahasa yang sangat penting dalam bahasa Go, yang membolehkan kami menunggu beberapa operasi komunikasi pada masa yang sama. Apabila berbilang operasi komunikasi sedia, pernyataan select
akan memilih pernyataan secara rawak untuk dilaksanakan.
Berikut ialah contoh menggunakan penyata select
, di mana kami menunggu untuk kedua-dua saluran menghantar dan menerima operasi:
package main import ( "fmt" ) func main() { ch1 := make(chan int) ch2 := make(chan int) go func() { ch1 <- 1 }() select { case x := <-ch1: fmt.Println(x) case ch2 <- 2: fmt.Println("send 2") } }
Dalam contoh di atas, kami menggunakan pernyataan go
untuk menunggu untuk yang baharu Laksanakan pernyataan ch1 <- 1
dalam coroutine. Kemudian, kami menggunakan pernyataan select
untuk menunggu saluran ch1
dan ch2
secara serentak. Jika terdapat elemen dalam ch1
, kita boleh mengeluarkannya daripada pernyataan x:= <-ch1
dan mencetaknya. Sebaliknya, jika ch2
boleh menghantar elemen, kemudian laksanakan ch2 <- 2
dan cetak output.
Perlu diingatkan bahawa apabila menggunakan penyata select
, kita tidak perlu melakukan operasi terima dan hantar pada semua saluran. Sebagai contoh, dalam contoh di atas kami hanya melakukan operasi penerimaan pada ch1
dan hanya melakukan operasi penghantaran pada ch2
.
Ringkasan:
Dalam bahasa Go, pemprosesan saluran tak segerak ialah teknologi yang sangat penting. Apabila pengaturcaraan secara tak segerak, kita boleh menggunakan saluran penimbal, saluran tertutup, saluran tamat masa, dsb. untuk menggunakan sepenuhnya ciri komunikasi saluran yang cekap. Pada masa yang sama, kita juga harus memberi perhatian kepada beberapa teknik, seperti hanya menutup saluran yang sedang digunakan oleh berbilang coroutine, menggunakan pernyataan select
, dsb. Sudah tentu, hanya beberapa teknik biasa yang diperkenalkan di sini Teknik pemprosesan saluran tak segerak perlu dipelajari dan diterokai oleh kami sendiri.
Atas ialah kandungan terperinci Teknik pemprosesan saluran tak segerak dalam bahasa Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!