GO 里面 MAP 如何實現 key 不存在 get 操作等待 直到 key 存在或者超時,保證并發安全,且需要實現以下接口:
~~~go
type sp interface {
Out(key string, val interface{}) //存入key /val,如果該key讀取的goroutine掛起,則喚醒。此方法不會阻塞,時刻都可以立即執行并返回
Rd(key string, timeout time.Duration) interface{} //讀取一個key,如果key不存在阻塞,等待key存在或者超時
}
~~~
**解析:**
看到阻塞協程第一個想到的就是`channel`,題目中要求并發安全,那么必須用鎖,還要實現多個`goroutine`讀的時候如果值不存在則阻塞,直到寫入值,那么每個鍵值需要有一個阻塞`goroutine`的`channel`。
實現如下:
~~~
type Map struct {
c map[string]*entry
rmx *sync.RWMutex
}
type entry struct {
ch chan struct{}
value interface{}
isExist bool
}
func (m *Map) Out(key string, val interface{}) {
m.rmx.Lock()
defer m.rmx.Unlock()
if e, ok := m.c[key]; ok {
e.value = val
e.isExist = true
close(e.ch)
} else {
e = &entry{ch: make(chan struct{}), isExist: true,value:val}
m.c[key] = e
close(e.ch)
}
}
func (m *Map) Rd(key string, timeout time.Duration) interface{} {
m.rmx.Lock()
if e, ok := m.c[key]; ok && e.isExist {
m.rmx.Unlock()
return e.value
} else if !ok {
e = &entry{ch: make(chan struct{}), isExist: false}
m.c[key] = e
m.rmx.Unlock()
fmt.Println("協程阻塞 -> ", key)
select {
case <-e.ch:
return e.value
case <-time.After(timeout):
fmt.Println("協程超時 -> ", key)
return nil
}
} else {
m.rmx.Unlock()
fmt.Println("協程阻塞 -> ", key)
select {
case <-e.ch:
return e.value
case <-time.After(timeout):
fmt.Println("協程超時 -> ", key)
return nil
}
}
}
~~~
- Golnag常見面試題目解析
- 交替打印數組和字母
- 判斷字符串中字符是否全都不同
- 翻轉字符串
- 判斷兩個給定的字符串排序后是否一致
- 字符串替換問題
- 機器人坐標計算
- 語法題目一
- 語法題目二
- goroutine和channel使用一
- 實現阻塞讀的并發安全Map
- 定時與 panic 恢復
- 高并發下的鎖與map讀寫問題
- 為 sync.WaitGroup 中Wait函數支持 WaitTimeout 功能.
- 七道語法找錯題目
- golang 并發題目測試
- 記一道字節跳動的算法面試題
- 多協程查詢切片問題
- 對已經關閉的的chan進行讀寫,會怎么樣?為什么?
- 簡單聊聊內存逃逸?
- 字符串轉成byte數組,會發生內存拷貝嗎?
- http包的內存泄漏