Tunggu nilai dalam peta tersedia dalam Go

王林
Lepaskan: 2024-02-05 21:51:07
ke hadapan
1212 orang telah melayarinya

等待映射中的值在 Go 中可用

Kandungan soalan

Saya mempunyai program yang pada asasnya melakukan tiga perkara - tetapkan nilai kunci, dapatkan nilai jika wujud atau tunggu sehingga nilai kunci yang diberikan tersedia. Fikiran awal saya - apabila mencipta kaedah dengan map[string]interface{} 的新类型 - 其中存储“持久”值。除此之外,为了等待一个值,我计划使用 map[string](chan struct{})。当调用 set() saya akan menulis ke saluran itu dan sesiapa yang menunggunya akan tahu nilainya ada.

Saya tidak tahu kunci sebelum ini - ia adalah rawak. Saya tidak pasti bagaimana untuk melaksanakan kaedah wait() dengan betul.

type Map struct {
    sync.Mutex

    m    map[string]interface{}
    wait map[string]chan (struct{})
}


func (m *Map) Set(key string, value interface{}) {
    m.ensureWaitChan(key)

    m.Lock()
    defer m.Unlock()

    m.m[key] = value

    // Signal to all waiting.
    m.wait[key] <- struct{}{}
}


func (m *Map) Wait(key string) interface{} {
    m.ensureWaitChan(key)

    m.Lock()
    
    value, ok := m.m[key]
    if ok {
        m.Unlock()
        return value
    }

    m.Unlock()
    // <------ Unlocked state where something might happen.
    <-m.wait[key]

    value := m.m[key]

    return value    
}

// If the channel does not exist for those waiting - create it.
func (m *Map) ensureWaitChan(key string) {
    m.Lock()
    defer m.Unlock()

    _, ok := m.wait[key]
    if ok {
        return
    }

    m.wait[key] = make(chan struct{}, 100)
}

Salin selepas log masuk

Masalahnya - terdapat keadaan perlumbaan dalam wait() - selepas saya melepaskan mutex, tetapi sebelum saya mula mendengar di saluran untuk nilai masuk.

Apakah cara terbaik untuk menangani masalah ini? Sebarang cadangan lain tentang cara untuk mencapai ini adalah dialu-alukan, saya pasti mesti ada cara yang lebih baik untuk melakukan ini. Saya tidak mengundi nilai pada selang tetap atau apa-apa seperti itu.


Jawapan betul


Apa yang anda cari ialah gabungan antara peta penyegerakan dan broker mesej. Kita boleh mencapai ini dengan memanfaatkan saluran komunikasi dan penyegerakan supaya pelanggan boleh menerima mesej sebaik sahaja ia diterbitkan (jika ia belum ada dalam cache).

type Map struct {
    sync.Mutex

    m    map[string]any
    subs map[string][]chan any
}

func (m *Map) Set(key string, value any) {
    m.Lock()
    defer m.Unlock()

    m.m[key] = value

    // Send the new value to all waiting subscribers of the key
    for _, sub := range m.subs[key] {
        sub <- value
    }
    delete(m.subs, key)
}

func (m *Map) Wait(key string) any {
    m.Lock()
    // Unlock cannot be deferred so we can unblock Set() while waiting

    value, ok := m.m[key]
    if ok {
        m.Unlock()
        return value
    }

    // if there is no value yet, subscribe to any new values for this key
    ch := make(chan any)
    m.subs[key] = append(m.subs[key], ch)
    m.Unlock()

    return <-ch
}
Salin selepas log masuk

Memandangkan pelanggan mesti membuka kunci mutex peta sementara menunggu, mereka tidak boleh mengakses mesej baharu yang ditambahkan pada peta dengan selamat. Kami menghantar nilai baharu terus kepada semua pelanggan melalui saluran mereka sendiri supaya kami tidak perlu menambah lebih banyak penyegerakan dalam set untuk memastikan semua pelanggan gembira sebelum membuka kunci peta itu sendiri. Membuka kunci peta lebih awal akan membolehkan pelanggan membacanya secara terus, tetapi juga akan membenarkan nilai baharu dimasukkan pada masa yang sama, mengakibatkan hasil yang tidak konsisten.

Versi berjalan, juga termasuk pelaksanaan map generik dengan parameter jenis: https://go.dev/play/p/an7vrspdgmo

Atas ialah kandungan terperinci Tunggu nilai dalam peta tersedia dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:stackoverflow.com
Kenyataan Laman Web ini
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
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan