Kaedah untuk melaksanakan kawalan konkurensi dalam bahasa go: 1. WaitGroup, pemprosesan tugasan berbilang goroutin mempunyai hubungan pergantungan atau penyambungan; kerja WaitGroup, Memenuhi fungsi Konteks; 3. Konteks, perambatan isyarat antara grout berbilang peringkat, termasuk perambatan metadata, pembatalan perambatan isyarat, kawalan tamat masa, dsb.
Persekitaran pengendalian artikel ini: Sistem Windows 10, versi go1.20, komputer dell g3.
Di Golang, anda boleh membuka goroutine melalui kata kunci go Oleh itu, anda boleh menulis kod serentak dalam Go. Tetapi bagaimana untuk mengawal secara berkesan groutines melaksanakan serentak ini?
Mengenai kawalan serentak, perkara pertama yang mungkin difikirkan oleh ramai orang ialah kunci. Golang juga menyediakan mekanisme berkaitan kunci, termasuk penyegerakan kunci mutex. Mutex dan penyegerakan kunci baca-tulis.RWMutex. Selain kunci, terdapat juga penyegerakan/atom operasi atom, dsb. Walau bagaimanapun, tumpuan mekanisme ini ialah keselamatan data serentak goroutine. Perkara yang ingin dibincangkan oleh artikel ini ialah kawalan tingkah laku serentak goroutine.
Dalam kawalan tingkah laku serentak goroutine, terdapat tiga cara biasa, iaitu WaitGroup, saluran dan Konteks.
WaitGroup terletak di bawah pakej penyegerakan adalah seperti berikut.
func main() { var wg sync.WaitGroup wg.Add(2) //添加需要完成的工作量2 go func() { wg.Done() //完成工作量1 fmt.Println("goroutine 1 完成工作!") }() go func() { wg.Done() //完成工作量1 fmt.Println("goroutine 2 完成工作!") }() wg.Wait() //等待工作量2均完成 fmt.Println("所有的goroutine均已完成工作!")}输出: //goroutine 2 完成工作! //goroutine 1 完成工作! //所有的goroutine均已完成工作!
WaitGroup ialah kaedah kawalan serentak yang amat sesuai untuk situasi di mana tugas tertentu memerlukan berbilang goroutin untuk berfungsi bersama-sama Setiap goroutine hanya boleh melakukan sebahagian daripada tugasan itu hanya apabila semua goroutine selesai selesai. Oleh itu, WaitGroup mempunyai makna yang sama dengan namanya, iaitu cara menunggu.
Walau bagaimanapun, dalam perniagaan sebenar, terdapat senario: apabila keperluan tertentu dipenuhi, goroutine tertentu perlu dimaklumkan secara aktif untuk tamat. Contohnya, jika kita memulakan goroutine pemantauan latar belakang, apabila pemantauan tidak lagi diperlukan, kita harus memberitahu goroutine pemantauan untuk ditamatkan, jika tidak, ia akan terus melahu dan menyebabkan kebocoran.
Untuk senario di atas, WaitGroup tidak boleh berbuat apa-apa. Kaedah paling mudah yang boleh difikirkan adalah untuk menentukan pembolehubah global dan memberitahunya dengan mengubahsuai pembolehubah ini di tempat lain agak menyusahkan. Dalam kes ini, saluran+pilihan boleh berguna.
func main() { exit := make(chan bool) go func() { for { select { case <-exit: fmt.Println("退出监控") return default: fmt.Println("监控中") time.Sleep(2 * time.Second) } } }() time.Sleep(5 * time.Second) fmt.Println("通知监控退出") exit <- true //防止main goroutine过早退出 time.Sleep(5 * time.Second)}输出: //监控中 //监控中 //监控中 //通知监控退出 //退出监控
Gabungan saluran+pilihan ini ialah cara yang lebih elegan untuk memberitahu goroutine tentang penghujungnya.
Walau bagaimanapun, penyelesaian ini juga mempunyai had. Cuba bayangkan, bagaimana jika terdapat banyak goroutine yang semuanya perlu dikawal untuk menamatkannya? Bagaimana jika gorouti ini melahirkan gorouti lain? Sudah tentu kita boleh menentukan banyak saluran untuk menyelesaikan masalah ini, tetapi rantaian perhubungan goroutine membawa kepada kerumitan senario ini.
Senario di atas adalah perkara biasa di bawah model seni bina CS. Dalam Go, goroutine (A) yang berasingan sering dibuka untuk setiap pelanggan untuk mengendalikan siri permintaannya, dan selalunya satu A juga akan meminta perkhidmatan lain (mulakan goroutine B yang lain), dan B juga boleh meminta goroutine C, C yang lain kemudian menghantar permintaan kepada pelayan Databse, sebagai contoh. Bayangkan apabila pelanggan memutuskan sambungan, A, B dan C yang dikaitkan dengannya perlu keluar serta-merta sebelum sistem boleh menuntut semula sumber yang diduduki oleh A, B dan C. Keluar dari A adalah mudah, tetapi bagaimana untuk memberitahu B dan C untuk juga keluar?
Pada masa ini, Konteks muncul.
func A(ctx context.Context, name string) { go B(ctx ,name) //A调用了B for { select { case <-ctx.Done(): fmt.Println(name, "A退出") return default: fmt.Println(name, "A do something") time.Sleep(2 * time.Second) } }}func B(ctx context.Context, name string) { for { select { case <-ctx.Done(): fmt.Println(name, "B退出") return default: fmt.Println(name, "B do something") time.Sleep(2 * time.Second) } }}func main() { ctx, cancel := context.WithCancel(context.Background()) go A(ctx, "【请求1】") //模拟client来了1个连接请求 time.Sleep(3 * time.Second) fmt.Println("client断开连接,通知对应处理client请求的A,B退出") cancel() //假设满足某条件client断开了连接,那么就传播取消信号,ctx.Done()中得到取消信号 time.Sleep(3 * time.Second)}输出: //【请求1】 A do something //【请求1】 B do something //【请求1】 A do something //【请求1】 B do something //client断开连接,通知对应处理client请求的A,B退出 //【请求1】 B退出 //【请求1】 A退出
Dalam contoh, permintaan sambungan disimulasikan daripada klien, dan Goroutine A dibuka dengan sewajarnya untuk pemprosesan A juga membolehkan A dan B menggunakan Konteks untuk penjejakan untuk memaklumkan pembatalan , kedua-dua goroutine ini akan ditamatkan.
Ini ialah keupayaan kawalan Konteks Ia seperti pengawal Selepas menekan suis, semua sub-Konteks berdasarkan Konteks ini atau yang diperoleh daripadanya Pada masa ini, operasi pembersihan boleh dilakukan . Akhirnya Lepaskan goroutine, yang menyelesaikan masalah goroutine yang tidak terkawal selepas permulaan.
Penggunaan Konteks yang terperinci adalah di luar skop artikel ini. Akan ada artikel susulan yang menerangkan secara khusus pakej Konteks, jadi nantikan.
Artikel ini menyenaraikan tiga mod kawalan gelagat serentak di Golang. Tiada perbezaan baik atau buruk antara mod, ia hanya bergantung pada penggunaan penyelesaian yang sesuai untuk senario yang berbeza. Dalam projek sebenar, pelbagai kaedah sering digunakan dalam kombinasi.
Di Golang, anda boleh membuka goroutine melalui kata kunci go Oleh itu, anda boleh menulis kod serentak dalam Go. Tetapi bagaimana untuk mengawal secara berkesan groutines melaksanakan serentak ini?
Mengenai kawalan konkurensi, ramai orang mungkin memikirkan kunci terlebih dahulu. Golang juga menyediakan mekanisme berkaitan kunci, termasuk penyegerakan kunci mutex. Mutex dan penyegerakan kunci baca-tulis.RWMutex. Selain kunci, terdapat juga penyegerakan/atom operasi atom, dsb. Walau bagaimanapun, tumpuan mekanisme ini ialah keselamatan data serentak goroutine. Perkara yang ingin dibincangkan oleh artikel ini ialah kawalan tingkah laku serentak goroutine.
Dalam kawalan tingkah laku serentak goroutine, terdapat tiga kaedah biasa, iaitu WaitGroup, saluran dan Konteks.
Atas ialah kandungan terperinci Cara melaksanakan kawalan konkurensi dalam bahasa go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!