Saluran Golang yang mendalam: Prinsip pelaksanaan dan cadangan pengoptimuman prestasi
Saluran Golang ialah komponen utama model konkurensi CSP dan jambatan untuk komunikasi antara Goroutines. Saluran kerap digunakan di Golang, dan amat penting untuk memahami prinsip pelaksanaan dalamannya. Artikel ini akan menganalisis pelaksanaan asas Saluran berdasarkan kod sumber Go 1.13.
Penggunaan asas Saluran
Sebelum menganalisis secara rasmi pelaksanaan Saluran, mari semak penggunaan asasnya:
package main import "fmt" func main() { c := make(chan int) go func() { c <- 1 // 发送操作 }() x := <-c // 接收操作 fmt.Println(x) }
Kod ini menunjukkan dua operasi asas Saluran:
- Kendalian hantar:
c
- Terima operasi:
x :=
Saluran dibahagikan kepada Saluran penimbal dan Saluran tidak penimbal. Kod di atas menggunakan Saluran bukan penimbal. Dalam Saluran tidak buffer, jika tiada Goroutine lain sedang menerima data, pengirim akan menyekat pada penyata hantar.
Anda boleh menentukan saiz penimbal apabila memulakan Saluran Sebagai contoh, make(chan int, 2)
menentukan saiz penimbal menjadi 2. Sebelum penimbal penuh, pengirim boleh menghantar data tanpa menyekat tanpa menunggu penerima bersedia. Tetapi jika penimbal penuh, pengirim akan tetap menyekat.
Fungsi pelaksanaan asas saluran
Sebelum menyelami kod sumber Saluran, anda perlu mencari lokasi pelaksanaan khusus Saluran di Golang. Apabila menggunakan Saluran, fungsi asas seperti runtime.makechan
, runtime.chansend
dan runtime.chanrecv
sebenarnya dipanggil.
Anda boleh menggunakan perintah go tool compile -N -l -S hello.go
untuk menukar kod kepada arahan pemasangan atau gunakan alat dalam talian Compiler Explorer (contohnya: go.godbolt.org/z/3xw5Cj). Dengan menganalisis arahan pemasangan, kita boleh menemui:
-
make(chan int)
sepadan dengan fungsiruntime.makechan
. c sepadan dengan fungsi <code>runtime.chansend
.x := sepadan dengan fungsi <code>runtime.chanrecv
.
Pelaksanaan fungsi ini terletak dalam runtime/chan.go
fail kod sumber Go.
Struktur saluran
make(chan int)
akan ditukar menjadi fungsi runtime.makechan
oleh pengkompil, dan tandatangan fungsinya adalah seperti berikut:
func makechan(t *chantype, size int) *hchan
Antaranya, t *chantype
ialah jenis elemen Saluran, size int
ialah saiz penimbal yang ditentukan pengguna (0 jika tidak dinyatakan), dan nilai pulangan ialah *hchan
. hchan
ialah struktur pelaksanaan dalaman Saluran di Golang, ditakrifkan seperti berikut:
type hchan struct { qcount uint // 缓冲区中已放入元素的数量 dataqsiz uint // 用户构造Channel时指定的缓冲区大小 buf unsafe.Pointer // 缓冲区 elemsize uint16 // 缓冲区中每个元素的大小 closed uint32 // Channel是否关闭,==0表示未关闭 elemtype *_type // Channel元素的类型信息 sendx uint // 缓冲区中发送元素的索引位置(发送索引) recvx uint // 缓冲区中接收元素的索引位置(接收索引) recvq waitq // 等待接收的Goroutine列表 sendq waitq // 等待发送的Goroutine列表 lock mutex }
Atribut dalam hchan
dibahagikan secara kasar kepada tiga kategori:
-
Atribut berkaitan penimbal: seperti
buf
,dataqsiz
,qcount
, dsb. Apabila saiz penimbal Saluran bukan 0, penimbal digunakan untuk menyimpan data yang akan diterima, dan dilaksanakan menggunakan penimbal cincin. -
Atribut berkaitan baris gilir menunggu:
recvq
mengandungi Goroutine menunggu untuk menerima data,sendq
mengandungi Goroutine menunggu untuk menghantar data.waitq
Dilaksanakan menggunakan senarai pautan berganda. -
Atribut lain: seperti
lock
,elemtype
,closed
, dsb.
makechan
terutamanya melaksanakan beberapa semakan kesahihan dan peruntukan memori atribut seperti penimbal dan hchan
, yang tidak akan dibincangkan secara mendalam di sini.
Berdasarkan analisis ringkas atribut hchan
, dapat dilihat bahawa terdapat dua komponen penting: penimbal dan giliran menunggu. Semua tingkah laku dan pelaksanaan hchan
berkisar pada dua komponen ini.
Penghantaran data saluran
Proses penghantaran dan penerimaan Saluran adalah sangat serupa. Analisis dahulu proses penghantaran Saluran (contohnya c ).
cuba menghantar data ke Saluran, jika baris gilir recvq
tidak kosong, Goroutine yang menunggu untuk menerima data akan dikeluarkan daripada pengepala recvq
dan data akan dihantar terus ke Goroutine. Kodnya adalah seperti berikut:
package main import "fmt" func main() { c := make(chan int) go func() { c <- 1 // 发送操作 }() x := <-c // 接收操作 fmt.Println(x) }
recvq
Mengandungi Goroutine menunggu untuk menerima data. Apabila Goroutine menggunakan operasi terima (seperti x := ), jika <code>sendq
tidak kosong pada masa ini, Goroutine akan diambil daripada sendq
dan data akan dihantar kepadanya.
Jika recvq
kosong, ini bermakna tiada Goroutine menunggu untuk menerima data pada masa ini dan Saluran akan cuba memasukkan data ke dalam penimbal:
func makechan(t *chantype, size int) *hchan
Fungsi kod ini sangat mudah, ia adalah untuk meletakkan data ke dalam penimbal. Proses ini melibatkan pengendalian penimbal cincin, dataqsiz
mewakili saiz penimbal yang ditentukan pengguna (lalai kepada 0 jika tidak dinyatakan).
Jika Saluran bukan penimbal digunakan atau penimbal penuh (c.qcount == c.dataqsiz
), data yang akan dihantar dan Goroutine semasa akan dibungkus ke dalam objek sudog
, diletakkan dalam sendq
dan arus Goroutine akan ditetapkan untuk menunggu Status:
type hchan struct { qcount uint // 缓冲区中已放入元素的数量 dataqsiz uint // 用户构造Channel时指定的缓冲区大小 buf unsafe.Pointer // 缓冲区 elemsize uint16 // 缓冲区中每个元素的大小 closed uint32 // Channel是否关闭,==0表示未关闭 elemtype *_type // Channel元素的类型信息 sendx uint // 缓冲区中发送元素的索引位置(发送索引) recvx uint // 缓冲区中接收元素的索引位置(接收索引) recvq waitq // 等待接收的Goroutine列表 sendq waitq // 等待发送的Goroutine列表 lock mutex }
goparkunlock
akan membuka kunci mutex input dan menggantung Goroutine semasa, menetapkannya kepada keadaan menunggu. gopark
dan goready
muncul secara berpasangan dan merupakan operasi timbal balik.
Dari perspektif pengguna, selepas memanggil gopark
, pernyataan kod untuk menghantar data akan disekat.
Terimaan data saluran
Proses penerimaan Saluran pada asasnya serupa dengan proses penghantaran, jadi saya tidak akan menerangkan butiran di sini. Operasi berkaitan penimbal yang terlibat dalam proses penerimaan akan diterangkan secara terperinci kemudian.
Perlu diambil perhatian bahawa keseluruhan proses penghantaran dan penerimaan Saluran dikunci menggunakan runtime.mutex
. runtime.mutex
ialah kunci ringan yang biasa digunakan dalam kod sumber berkaitan masa jalan Keseluruhan proses bukanlah penyelesaian tanpa kunci yang paling berkesan. Terdapat isu tentang Saluran tanpa kunci di Golang: go/issues#8899.
Pelaksanaan penimbal cincin saluran
Saluran menggunakan penimbal cincin untuk menyimpan data bertulis. Penampan gelang mempunyai banyak kelebihan dan sesuai untuk melaksanakan baris gilir FIFO panjang tetap.
Pelaksanaan penimbal cincin dalam Saluran adalah seperti berikut:
Terdapat dua pembolehubah berkaitan penimbal dalamhchan
: recvx
dan sendx
. sendx
mewakili indeks boleh tulis dalam penimbal dan recvx
mewakili indeks boleh dibaca dalam penimbal. Elemen antara recvx
dan sendx
mewakili data yang telah dimasukkan ke dalam penimbal seperti biasa.

Anda boleh terus menggunakan buf[recvx]
untuk membaca elemen pertama baris gilir dan gunakan buf[sendx] = x
untuk meletakkan elemen di penghujung baris gilir.
Tulisan penimbal
Apabila penimbal tidak penuh, operasi memasukkan data ke dalam penimbal adalah seperti berikut:
package main import "fmt" func main() { c := make(chan int) go func() { c <- 1 // 发送操作 }() x := <-c // 接收操作 fmt.Println(x) }
chanbuf(c, c.sendx)
bersamaan dengan c.buf[c.sendx]
. Proses di atas sangat mudah, hanya salin data ke lokasi penimbal sendx
.
Kemudian, gerakkan sendx
ke kedudukan seterusnya. Jika sendx
mencapai kedudukan terakhir, ia ditetapkan kepada 0, iaitu pendekatan hujung ke hujung biasa.
Bacaan penimbal
Apabila buffer tidak penuh, sendq
juga mesti kosong (kerana jika buffer tidak penuh, Goroutine yang menghantar data tidak akan beratur, tetapi akan terus memasukkan data ke dalam buffer). Pada masa ini, logik bacaan Saluran chanrecv
adalah agak mudah Data boleh dibaca terus dari penimbal Ia juga merupakan proses memindahkan recvx
, yang pada asasnya sama dengan penulisan penimbal di atas.
Apabila terdapat Goroutine menunggu dalam sendq
, penimbal mesti penuh pada masa ini. Pada masa ini, logik bacaan Saluran adalah seperti berikut:
func makechan(t *chantype, size int) *hchan
ep
ialah alamat yang sepadan dengan pembolehubah yang menerima data (contohnya, dalam x := , <code>ep
ialah alamat x
). sg
mewakili sendq
pertama yang diambil daripada sudog
. Dalam kod:
-
typedmemmove(c.elemtype, ep, qp)
bermaksud menyalin elemen yang boleh dibaca pada masa ini dalam penimbal ke alamat pembolehubah penerima. -
typedmemmove(c.elemtype, qp, sg.elem)
bermaksud menyalin data yang menunggu untuk dihantar oleh Goroutine dalamsendq
ke penimbal. Keranarecv
dilaksanakan kemudian, ia sama dengan meletakkan data dalamsendq
pada penghujung baris gilir.
Ringkasnya, di sini Saluran menyalin data pertama dalam penimbal kepada pembolehubah penerima yang sepadan, dan pada masa yang sama menyalin elemen dalam sendq
ke penghujung baris gilir, dengan itu melaksanakan FIFO (masuk dahulu, keluar dahulu) .
Ringkasan
Saluran ialah salah satu kemudahan yang paling biasa digunakan di Golang. Memahami kod sumbernya akan membantu anda menggunakan dan memahami Saluran dengan lebih baik. Pada masa yang sama, jangan terlalu percaya karut dan bergantung pada prestasi Saluran Reka bentuk semasa Saluran masih mempunyai banyak ruang untuk pengoptimuman.
Cadangan pengoptimuman:
- Gunakan mekanisme penguncian yang lebih ringan atau skema bebas kunci untuk meningkatkan prestasi.
- Optimumkan pengurusan penimbal dan kurangkan peruntukan memori dan operasi penyalinan.
Leapcell: Platform tanpa pelayan terbaik untuk aplikasi web Golang

Akhir sekali, saya mengesyorkan platform yang sangat sesuai untuk menggunakan perkhidmatan Go: Leapcell
- Sokongan berbilang bahasa: Menyokong pembangunan JavaScript, Python, Go atau Rust.
- Gunakan projek tanpa had secara percuma: Bayar hanya untuk apa yang anda gunakan, tiada permintaan, tiada bayaran.
- Sangat menjimatkan kos: Bayar semasa anda pergi, tiada yuran terbiar. Contohnya: $25 menyokong 6.94 juta permintaan dengan purata masa tindak balas 60 milisaat.
- Pengalaman pembangun yang lancar: UI intuitif untuk persediaan mudah; saluran paip CI/CD automatik sepenuhnya dan metrik dan log masa nyata untuk cerapan yang boleh diambil tindakan.
- Skala mudah dan prestasi tinggi: Skala secara automatik untuk mudah mengendalikan overhed operasi sifar, fokus pada pembinaan.

Sila semak dokumentasi untuk maklumat lanjut!
Twitter Leapcell: https://www.php.cn/link/7884effb9452a6d7a7a79499ef854afd
Atas ialah kandungan terperinci Pergi Saluran Dibuka Kunci: Cara Ia Berfungsi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Goisidealforbuildingscalablesystemsduetoitssimplicity, ecurciency, dan barangan-inconcurrencysupport.1) go'ScleansyntaxandminimalisticdesignenhanceProductivityandreduceerrors.2)

InitFunctionsingorunautomaticallybeforemain () andareuseforforsettingupenvironmentsandinitializingvariables.usethemforsimpletasks, mengelakkansidefefects, andbecautiouswithtestingandloggingtomaintaincodeclarityAndestability.

GoinitializespackagesintheordertheyareImported, thenexecutesinitfunctionswithinapackageintheirdefinitionorder, danfilenamesdeterminetheorderacrossmultiplefiles

CustomInterfacesingoarecrucialForWritingFlexible, diselenggara, danTestableCode.theYenabledEveloperStofocusonbehavioroverImplementation, enhancingmodularityandrobustness.bydefiningmethodsignaturesthattypesmustimplement, interfacesallowforcorcodforcodforcodforcodforcodforcodforcodforcodeShorcodeShorcodforcodforcodeShorcodeShorcodeShorcodeShorcodeShorcodeAdeShorcodeShorcodeSoUsVorcoShorcodeS

Alasan untuk menggunakan antara muka untuk simulasi dan ujian adalah bahawa antara muka membolehkan definisi kontrak tanpa menentukan pelaksanaan, menjadikan ujian lebih terpencil dan mudah dikekalkan. 1) Pelaksanaan antara muka yang tersirat menjadikannya mudah untuk membuat objek mengejek, yang dapat menggantikan pelaksanaan sebenar dalam ujian. 2) Menggunakan antara muka dengan mudah boleh menggantikan pelaksanaan sebenar perkhidmatan dalam ujian unit, mengurangkan kerumitan ujian dan masa. 3) Fleksibiliti yang disediakan oleh antara muka membolehkan perubahan dalam tingkah laku simulasi untuk kes ujian yang berbeza. 4) Antara muka membantu reka bentuk kod yang boleh diuji dari awal, meningkatkan modulariti dan mengekalkan kod.

Di GO, fungsi INIT digunakan untuk permulaan pakej. 1) Fungsi init secara automatik dipanggil apabila permulaan pakej, dan sesuai untuk memulakan pembolehubah global, menetapkan sambungan dan memuatkan fail konfigurasi. 2) Terdapat pelbagai fungsi init yang boleh dilaksanakan dalam urutan fail. 3) Apabila menggunakannya, perintah pelaksanaan, kesukaran ujian dan kesan prestasi harus dipertimbangkan. 4) Adalah disyorkan untuk mengurangkan kesan sampingan, menggunakan suntikan ketergantungan dan penangguhan permulaan untuk mengoptimumkan penggunaan fungsi INIT.

Go'sSelectStatementStreamLinesConcurrentProgrammingByMultiPlexingOperations.1) itAllowSwaitingonMultiPlechannoPerations,

ContextandWaitGroupSarecrucialingingoformanagingGoroutinesfectively.1) ContextAllowsSignalingCancellationandDeadlinesacrosapiboundaries, memastikangoroutinescanbestplygracely.2) WaitgroupSsynchronizegoroutine, Mempersembahkan CreationAllcebeBefefeSproprophering, Preveation


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

PhpStorm versi Mac
Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 Linux versi baharu
SublimeText3 Linux versi terkini

mPDF
mPDF ialah perpustakaan PHP yang boleh menjana fail PDF daripada HTML yang dikodkan UTF-8. Pengarang asal, Ian Back, menulis mPDF untuk mengeluarkan fail PDF "dengan cepat" dari tapak webnya dan mengendalikan bahasa yang berbeza. Ia lebih perlahan dan menghasilkan fail yang lebih besar apabila menggunakan fon Unicode daripada skrip asal seperti HTML2FPDF, tetapi menyokong gaya CSS dsb. dan mempunyai banyak peningkatan. Menyokong hampir semua bahasa, termasuk RTL (Arab dan Ibrani) dan CJK (Cina, Jepun dan Korea). Menyokong elemen peringkat blok bersarang (seperti P, DIV),

Penyesuai Pelayan SAP NetWeaver untuk Eclipse
Integrasikan Eclipse dengan pelayan aplikasi SAP NetWeaver.
