GO里面MAP如何实现key不存在 get操作等待 直到key存在或者超时,保证并发安全

发布于 2022-09-11 18:32:12 字数 253 浏览 15 评论 0

保证并发安全,实现如下接口

type sp interface {
    Out(key string, val interface{})  //存入key /val,如果该key读取的goroutine挂起,则唤醒。此方法不会阻塞,时刻都可以立即执行并返回
    Rd(key string, timeout time.Duration) interface{}  //读取一个key,如果key不存在阻塞,等待key存在或者超时
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温柔嚣张 2022-09-18 18:32:12

写了一段代码,不知道是否符合你的要求:

func main() {
    m := make(map[string]int)
    keyChan := make(chan string)
    valChan := make(chan int)
    var wg sync.WaitGroup
    var l sync.RWMutex
    done := make(chan struct{})

    for i := 0; i < 3; i++ {
        go func(i int) {
            key := "test" + strconv.Itoa(i)
            l.RLock()
            v, ok := m[key]
            l.RUnlock()
            if !ok {
                wg.Add(1)
                go func() {
                    keyChan <- key
                    defer wg.Done()
                    timeout := time.After(10 * time.Second)
                    select {
                    case <-timeout:
                        log.Panic("wait too long!")
                    case v := <-valChan:
                        log.Printf("val is %d\n", v)
                    }
                }()
                wg.Wait()
            } else {
                log.Printf("val is %d\n", v)
            }
            done <- struct{}{}
        }(i)
    }

    go func() {
        rand.Seed(time.Now().Unix())
        for {
            select {
            case k := <-keyChan:
                time.Sleep(2 * time.Second)
                l.Lock()
                v := rand.Intn(100)
                m[k] = v
                l.Unlock()
                valChan <- v
            default:

            }
        }
    }()

    select {}
}
千纸鹤 2022-09-18 18:32:12

可以利用channel关闭goroutine不阻塞特性来实现:

下面的代码可以实现你的需求,只是没有写key被多次写入的判断逻辑。

type sp interface {
    Out(key string, val interface{})                  //存入key /val,如果该key读取的goroutine挂起,则唤醒。此方法不会阻塞,时刻都可以立即执行并返回
    Rd(key string, timeout time.Duration) interface{} //读取一个key,如果key不存在阻塞,等待key存在或者超时
}

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
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文