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