Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Artikel untuk membincangkan masalah persaingan sumber dalam bahasa Go

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa Go

青灯夜游
青灯夜游ke hadapan
2023-02-17 14:40:203225semak imbas

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa Go

Kita semua tahu bahawa keselamatan thread adalah sangat penting dalam pengaturcaraan serentak. Seterusnya, kami akan menganggap senario untuk menghasilkan semula urutan situasi yang tidak selamat, dan kemudian bercakap tentang cara menyelesaikan senario

dalam Go

Kita kini perlu menangani 1 ~ 100 untuk mencari faktorial mereka dan meletakkan hasilnya ke dalam peta

1! = 1 = 1
2! = 1 * 2 = 2
3! = 1 * 2 * 3 = 6
4! = 1 * 2 * 3 * 4 = 24
5! = 1 * 2 * 3 * 4 * 5 = 120
...
{
    1: 1
    2: 2
    3: 6
    4: 24
    5: 120
    ...
}

Pelaksanaan kod

var factorialMap = make(map[int]int)

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
        result *= i
    }
    factorialMap[n] = result
}

func main() {
    for i := 1; i < 10; i++ {
        Factorial(i)
    }
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa GoHasil pelaksanaan kod di atas sebenarnya tidak Persoalannya, kenapa ada gangguan? Kerana ini peta dalam bahasa Go, ia sebenarnya tidak teratur mengikut pemahaman kami, yang pertama disimpan, pertama keluar, tetapi maaf, peta Golang tidak seperti ini. Tiada masalah dengan pelaksanaan di atas Pelajar yang berhati-hati mungkin mendapati bahawa versi kod ini tidak menggunakan konkurensi, bukan? Baiklah, mari kita teruskan perbaiki

Pelaksanaan serentak

var factorialMap = make(map[int]int)

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
        result *= i
    }
    factorialMap[n] = result
}

func main() {
    for i := 1; i < 10; i++ {
        go Factorial(i)
    }
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa GoKita dapati bahawa versi serentak menambah a di hadapan panggilan untuk mengira faktorial fungsi goItu sahaja. Jangan memandang rendah ini go, ini terlalu mengada-ada Sudah tentu, semua orang tahu bahawa ini adalah kata kunci untuk memulakan coroutine dalam bahasa Go.

Hasil pelaksanaan ialah tiada apa-apa keluaran kepada konsol Ini kerana hubungan pelaksanaan antara coroutine utama dan sub-coroutine Mari kita lukis gambar untuk memahami

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa Go Daripada gambar di atas, kita boleh didapati bahawa masa pelaksanaan coroutine utama adalah pendek (ditunjukkan sebagai relatif singkat), dan masa pelaksanaan sub-coroutine adalah agak panjang (ditunjukkan sebagai agak panjang) Kita mesti ingat bahawa sub-coroutine adalah relatif kepada coroutine utama semasa Jika coroutine utama tidak wujud lagi, tidak akan ada sub-coroutine

Jadi kod di atas tidak menghasilkan apa-apa dilaksanakan, tetapi sub-coroutine belum selesai Jika sub-coroutine belum selesai, bolehkah ada apa-apa dalam factorialMap?

Subcoroutine utama dan lain-lain

Ini membawa kepada soalan pertama kami, bagaimanakah coroutine utama menunggu sub-coroutine selesai melaksanakan sebelum keluar dari program. Kami kini menggunakan cara yang paling mudah dan paling mudah untuk memikirkan

var factorialMap = make(map[int]int)

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
        result *= i
    }
    factorialMap[n] = result
}

func main() {
    for i := 1; i < 100; i++ {
        go Factorial(i)
    }
    time.Sleep(time.Second * 3)
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa GoApabila bilangan penyelarasan agak kecil, masalah ini mungkin tidak berlaku Sebaik sahaja bilangan penyelarasan menjadi besar, masalah akan berlaku muncul serta-merta.

Hasil pelaksanaan dalam gambar ialah Kesilapan penulisan peta serentakMengapa masalah ini berlaku? Tetapi jika 100 orang mengambil buah dari bakul, akan ada masalah Pertama, mungkin tidak cukup buah dalam bakul, kedua, semua orang mahu mengambilnya, yang pasti akan menimbulkan persaingan.

Pengoptimuman Masalah 1

Memandangkan masalah di atas, kami memperkenalkan konsep kunci global. Ini agak-agak bila kita pergi tandas 100 orang nak guna tandas, tapi siapa yang ambik dulu dia yang pergi dulu, dan orang ni pun kunci tandas untuk menghalang orang lain masuk

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa Go

var factorialMap = make(map[int]int)
var lock sync.Mutex

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
            result *= i
    }
    // defer 不好理解
    // defer func(){
    // 	lock.Unlock() // 执行完解锁
    // }()
    lock.Lock() // 执行时上锁
    factorialMap[n] = result
    lock.Unlock() // 执行后解锁
}

func main() {
    for i := 1; i < 100; i++ {
        go Factorial(i)
    }
    time.Sleep(time.Second * 3)
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa GoHasil pelaksanaan 0 mungkin disebabkan oleh jenis data yang tidak dapat disimpan Anda tidak perlu risau tentang perkara ini

Artikel untuk membincangkan masalah persaingan sumber dalam bahasa GoDengan cara ini, kami telah menyelesaikan masalah persaingan sumber. Tetapi sebenarnya ada masalah lain, iaitu, kita masih perlu menunggu secara manual di coroutine utama, yang sangat buruk Bagaimana jika sub-coroutine tidak dapat menyelesaikannya dalam masa 3 saat?

Pengoptimuman Masalah 2

Masalah ini ialah kita tidak mahu menunggu sub-coroutine secara manual dalam coroutine utama dengan kata lain, kita tidak 'Tidak mahu terus menulisnya dalam kod Berapa lama menunggu

Di sini kami telah memperkenalkan prinsip dalamanWaitGroup

var factorialMap = make(map[int]int)
var lock sync.Mutex
var wg sync.WaitGroup

func Factorial(n int) {
    result := 1
    for i := 1; i <= n; i++ {
        result *= i
    }
    lock.Lock() // 执行时上锁
    factorialMap[n] = result
    lock.Unlock() // 执行后解锁
    wg.Done()
}

func main() {
    for i := 1; i < 100; i++ {
        wg.Add(1)
        go Factorial(i)
    }
    wg.Wait()
    for k, v := range factorialMap {
        fmt.Printf("%d 的阶乘是%d\n", k, v)
    }
}

WaitGroup. Anda boleh mempelajarinya sendiri, saya tidak akan masuk ke dalamnya sekarang. Ringkasnya, WaitGroup ialah bakul Setiap kali coroutine dibuka, pengecam ditambahkan pada bakul (Tambah fungsi setiap kali coroutine dilaksanakan, pengecam akan ditolak daripada bakul (Fungsi Selesai). Semak bakul. Jika kosong, ini bermakna coroutine telah dilaksanakan (fungsi Tunggu)

[Pembelajaran yang disyorkan: pergi tutorial video]

Atas ialah kandungan terperinci Artikel untuk membincangkan masalah persaingan sumber dalam bahasa Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.cn. Jika ada pelanggaran, sila hubungi admin@php.cn Padam