cari
Rumahpembangunan bahagian belakangGolangPergi Saluran Dibuka Kunci: Cara Ia Berfungsi

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 fungsi runtime.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. waitqDilaksanakan menggunakan senarai pautan berganda.
  • Atribut lain: seperti lock, elemtype, closed, dsb.
Fungsi

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 ).

Apabila

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 dalam

hchan: 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.

Go Channel Unlocked: How They Work

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 dalam sendq ke penimbal. Kerana recv dilaksanakan kemudian, ia sama dengan meletakkan data dalam sendq 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

Go Channel Unlocked: How They Work

Akhir sekali, saya mengesyorkan platform yang sangat sesuai untuk menggunakan perkhidmatan Go: Leapcell

  1. Sokongan berbilang bahasa: Menyokong pembangunan JavaScript, Python, Go atau Rust.
  2. Gunakan projek tanpa had secara percuma: Bayar hanya untuk apa yang anda gunakan, tiada permintaan, tiada bayaran.
  3. Sangat menjimatkan kos: Bayar semasa anda pergi, tiada yuran terbiar. Contohnya: $25 menyokong 6.94 juta permintaan dengan purata masa tindak balas 60 milisaat.
  4. 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.
  5. Skala mudah dan prestasi tinggi: Skala secara automatik untuk mudah mengendalikan overhed operasi sifar, fokus pada pembinaan.
Go Channel Unlocked: How They Work

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!

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
Membina sistem berskala dengan bahasa pengaturcaraan GoMembina sistem berskala dengan bahasa pengaturcaraan GoApr 25, 2025 am 12:19 AM

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

Amalan terbaik untuk menggunakan fungsi init dengan berkesan di GOAmalan terbaik untuk menggunakan fungsi init dengan berkesan di GOApr 25, 2025 am 12:18 AM

InitFunctionsingorunautomaticallybeforemain () andareuseforforsettingupenvironmentsandinitializingvariables.usethemforsimpletasks, mengelakkansidefefects, andbecautiouswithtestingandloggingtomaintaincodeclarityAndestability.

Perintah pelaksanaan fungsi init dalam pakej GoPerintah pelaksanaan fungsi init dalam pakej GoApr 25, 2025 am 12:14 AM

GoinitializespackagesintheordertheyareImported, thenexecutesinitfunctionswithinapackageintheirdefinitionorder, danfilenamesdeterminetheorderacrossmultiplefiles

Menentukan dan menggunakan antara muka tersuai di GOMenentukan dan menggunakan antara muka tersuai di GOApr 25, 2025 am 12:09 AM

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

Menggunakan antara muka untuk mengejek dan menguji di GOMenggunakan antara muka untuk mengejek dan menguji di GOApr 25, 2025 am 12:07 AM

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.

Menggunakan init untuk permulaan pakej di GoMenggunakan init untuk permulaan pakej di GoApr 24, 2025 pm 06:25 PM

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.

Pernyataan Pilih Go: Pelbagai operasi serentakPernyataan Pilih Go: Pelbagai operasi serentakApr 24, 2025 pm 05:21 PM

Go'sSelectStatementStreamLinesConcurrentProgrammingByMultiPlexingOperations.1) itAllowSwaitingonMultiPlechannoPerations,

Teknik Konvensyen Lanjutan di GO: Konteks dan WaitgroupsTeknik Konvensyen Lanjutan di GO: Konteks dan WaitgroupsApr 24, 2025 pm 05:09 PM

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

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

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

Alat panas

PhpStorm versi Mac

PhpStorm versi Mac

Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 Linux versi baharu

SublimeText3 Linux versi baharu

SublimeText3 Linux versi terkini

mPDF

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

Penyesuai Pelayan SAP NetWeaver untuk Eclipse

Integrasikan Eclipse dengan pelayan aplikasi SAP NetWeaver.