使用锁从地图读取不会通过通道返回值



我试图在golang中实现从地图读取/写入的锁定版本,但它没有返回所需的结果。

包主

import (
    "sync"
    "fmt"
)
var m = map[int]string{}
var lock = sync.RWMutex{}
func StoreUrl(id int, url string) {
        for {
                lock.Lock()
                defer lock.Unlock()
                m[id] = url
        }
}
func LoadUrl(id int, ch chan string) {
    for {
        lock.RLock()
        defer lock.RUnlock()
        r := m[id]
        ch <- r
    }
}
func main() {
    go StoreUrl(125, "www.google.com")
    chb := make(chan string)
    go LoadUrl(125, chb);
    C := <-chb
    fmt.Println("Result:", C)                           
}

输出为:

Result: 

这意味着该值不会通过通道返回,但我没有得到。没有锁定/执行例程,它似乎可以正常工作。我做错了什么?

代码也可以在这里找到:

https://play.golang.org/p/-WmRcMty5B

没有睡眠或某种 IO 的无限循环总是坏主意。

在你的代码中,如果你把一个 print 语句放在 StoreUrl 的开头,你会发现它永远不会被打印,即 go 例程从未启动,go 调用正在设置将有关这个新 go 例程的信息放在 go 调度程序的某个运行队列中,但调度器尚未运行以调度该任务。如何运行调度程序?执行睡眠/IO/通道读取/写入。

另一个问题是您的无限循环正在锁定并尝试再次锁定,这将导致它死锁。延迟仅在函数退出后运行,并且由于无限循环,该函数永远不会退出。

下面是修改后的代码,它使用 sleep 来确保每个执行线程都有时间完成其工作。

package main
import (
    "sync"
    "fmt"
    "time"
)
var m = map[int]string{}
var lock = sync.RWMutex{}
func StoreUrl(id int, url string) {
        for {
                lock.Lock()
                m[id] = url
                lock.Unlock()
                time.Sleep(1)
        }
}
func LoadUrl(id int, ch chan string) {
    for {
            lock.RLock()
            r := m[id]
            lock.RUnlock()
            ch <- r
    }
}
func main() {
    go StoreUrl(125, "www.google.com")
    time.Sleep(1)
    chb := make(chan string)
    go LoadUrl(125, chb);
    C := <-chb
    fmt.Println("Result:", C)
}

编辑:正如评论中@Jaun提到的,您也可以使用runtime.Gosched()而不是睡眠。

defer 的用法不正确,在函数结束时延迟执行,而不是 for 语句。

func StoreUrl(id int, url string) {
    for {
        func() {
            lock.Lock()
            defer lock.Unlock()
            m[id] = url
        }()
    }
}

func StoreUrl(id int, url string) {
    for {
        lock.Lock()
        m[id] = url
        lock.Unlock()
    }
}

我们无法控制 go 例程的顺序,因此请添加时间。Sleep() 来控制顺序。

代码在这里:

https://play.golang.org/p/Bu8Lo46SA2

最新更新