Golang, sebagai bahasa pengaturcaraan yang agak muda, telah menarik lebih banyak perhatian dan kasih sayang dengan perkembangan pesatnya sejak beberapa tahun kebelakangan ini. Mekanisme konkurensi terbina dalam Golang menjadikannya disukai oleh ramai pembangun, tetapi penggunaan mekanisme konkurensi akan menyebabkan beberapa bahaya tersembunyi, terutamanya apabila konkurensi tidak selamat, ia mungkin menyebabkan beberapa masalah dalam program. Artikel ini akan meneroka sebab dan penyelesaian untuk konkurensi yang tidak selamat di Golang.
1. Sebab mengapa concurrency tidak selamat
1 Keadaan perlumbaan
Syarat perlumbaan merujuk kepada apabila berbilang rangkaian mengakses sumber yang dikongsi, disebabkan oleh operasi yang berbeza, hasil Kekacauan berlaku, keadaan yang dipanggil keadaan perlumbaan. Di Golang, keadaan perlumbaan lebih jelas disebabkan oleh pelaksanaan coroutine yang tidak segerak.
2. Pertandingan data
Persaingan data bermakna berbilang coroutine mengakses kawasan memori yang sama pada masa yang sama, dan sekurang-kurangnya satu coroutine sedang menjalankan operasi tulis. Disebabkan oleh mekanisme konkurensi Golang, coroutine yang berbeza mempunyai masa pelaksanaan yang berbeza, jadi berbilang coroutine boleh mengubah suai kawasan memori yang sama pada masa yang sama.
3. Deadlock
Deadlock merujuk kepada situasi di mana dua atau lebih coroutine sedang menunggu antara satu sama lain untuk melepaskan sumber dan tidak dapat meneruskan pelaksanaan. Keadaan ini mungkin berlaku apabila menggunakan kunci Jika kunci digunakan secara tidak betul, jalan buntu akan berlaku.
2. Contoh konkurensi tidak selamat di Golang
Berikut ialah contoh mudah untuk menjelaskan masalah konkurensi tidak selamat di Golang:
package main import ( "fmt" "sync" ) var num = 0 func add(wg *sync.WaitGroup) { num++ wg.Done() } func main() { var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go add(&wg) } wg.Wait() fmt.Println("num=", num) }
Dalam contoh ini, kami Nombor pembolehubah global ditakrifkan dan coroutine digunakan untuk memanggil kaedah tambah untuk menambah nombor 1000 kali. Disebabkan oleh pelaksanaan tak segerak bagi coroutine, susunan pelaksanaan program ini tidak pasti. Jika kod ini menjalankan berbilang coroutine pada masa yang sama, persaingan data akan berlaku dan hasil num mungkin bukan 1000 yang kami jangkakan.
3. Bagaimana untuk mengelakkan konkurensi yang tidak selamat di Golang
1 Gunakan kunci
Kunci adalah salah satu kaedah yang biasa digunakan untuk menyelesaikan masalah konkurensi yang tidak selamat kunci Pelaksanaan, seperti sync.Mutex, sync.RWMutex, dsb. Penggunaan kunci boleh memastikan bahawa hanya satu coroutine boleh mengakses sumber tertentu pada masa yang sama, dengan itu mengelakkan berlakunya persaingan data.
Ubah suai contoh di atas dan gunakan penyegerakan.Mutex untuk mengelakkan perlumbaan data:
package main import ( "fmt" "sync" ) var num = 0 func add(wg *sync.WaitGroup, lock *sync.Mutex) { lock.Lock() num++ lock.Unlock() wg.Done() } func main() { var wg sync.WaitGroup var lock sync.Mutex for i := 0; i < 1000; i++ { wg.Add(1) go add(&wg, &lock) } wg.Wait() fmt.Println("num=", num) }
Dalam contoh ini, kami menggunakan penyegerakan.Mutex untuk memastikan pengubahsuaian kepada num adalah atom . Ini mengelakkan berlakunya perlumbaan data.
2. Gunakan operasi atom
Golang menyediakan satu siri operasi atom untuk memastikan bahawa operasi sumber tertentu adalah atom. Gunakan operasi atom untuk mengelakkan keadaan perlumbaan, seperti AddInt32, AddInt64, SwapInt32, SwapInt64, dsb. dalam pakej penyegerakan/atomik.
Ubah suai contoh di atas dan gunakan operasi atom untuk mengelakkan perlumbaan data:
package main import ( "fmt" "sync/atomic" "sync" ) var num int32 func add(wg *sync.WaitGroup) { atomic.AddInt32(&num,1) wg.Done() } func main() { var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go add(&wg) } wg.Wait() fmt.Println("num=", num) }
Dalam contoh ini, kami menggunakan fungsi AddInt32 dalam pakej penyegerakan/atomik untuk memastikan pengubahsuaian kepada nombor adalah Atom, mengelakkan keadaan perlumbaan.
3. Gunakan saluran
Saluran ialah mekanisme penyegerakan yang sangat biasa digunakan dalam pengaturcaraan serentak Golang boleh memastikan bahawa komunikasi antara coroutine disegerakkan, dengan itu mengelakkan keadaan perlumbaan dan isu Pertandingan data.
Ubah suai contoh di atas untuk menggunakan saluran bagi mengelakkan perlumbaan data:
package main import ( "fmt" "sync" ) func add(wg *sync.WaitGroup, ch chan int) { ch <- 1 wg.Done() } func main() { var wg sync.WaitGroup ch := make(chan int, 1000) for i := 0; i < 1000; i++ { wg.Add(1) go add(&wg, ch) } wg.Wait() close(ch) num := 0 for n := range ch { num += n } fmt.Println("num=", num) }
Dalam contoh ini, kami menggunakan saluran untuk memastikan pengubahsuaian kepada num disegerakkan, sekali gus mengelakkan penampilan perlumbaan data .
4. Ringkasan
Mekanisme konkurensi Golang adalah salah satu ciri yang sangat menarik, tetapi penggunaan mekanisme konkurensi juga membawa isu keselamatan tertentu. Artikel ini membincangkan sebab dan penyelesaian bagi keadaan Golang yang tidak selamat, dan menyediakan penyelesaian terutamanya dari aspek mengelakkan persaingan data, keadaan perlumbaan dan kebuntuan secara serentak. Dalam proses pengaturcaraan sebenar, kita boleh memilih mekanisme yang sesuai mengikut keperluan khusus untuk memastikan kualiti dan keselamatan program.
Atas ialah kandungan terperinci Adakah Golang concurrency tidak selamat?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!