V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
gramyang
V2EX  ›  Go 编程语言

关于 golang 互斥锁的一个疑问

  •  
  •   gramyang · 2019-07-08 13:20:29 +08:00 · 3139 次点击
    这是一个创建于 2000 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码见 https://github.com/GramYang/GoTest/blob/master/sync/mutex1.go

    第一个 test 输出的是小于 1000 的随机值。 第二个 test 稳定输出 1000,但是限制了原生线程的数量,这在工作环境中显然是不可能的。 第三个 test 稳定输出 1000,方法和我之前用过的 currenthashmap 的用法一样。这里已经去掉了互斥锁。

    那么问题来了:既然互斥锁锁的只是 goroutine,而多个原生线程并发仍然会产生并发错误,那么到底该怎么正确使用互斥锁呢?

    第 1 条附言  ·  2019-07-08 14:00:39 +08:00
    把锁换成指针传递成功了。。。。

    看来还是我的理解有问题,互斥锁并不是 goroutine 级别的。。。。
    6 条回复    2019-07-08 18:06:24 +08:00
    Maboroshii
        1
    Maboroshii  
       2019-07-08 13:47:54 +08:00
    下面是 go playground 的输出。
    func passes lock by value: sync.Mutex
    这一句, 锁不能用值传递, 改成全局变量或者放在结构体里面再试。


    ./prog.go:38:8: call of func(i int, m sync.Mutex) {
    fmt.Println("Not lock: ", i)
    mutex.Lock()
    fmt.Println("Lock: ", i)
    time.Sleep(time.Second)
    fmt.Println("Unlock: ", i)
    mutex.Unlock()
    defer wait.Done()
    } copies lock value: sync.Mutex
    ./prog.go:30:20: func passes lock by value: sync.Mutex
    ./prog.go:58:8: call of func(c *counter, m sync.Mutex) {
    m.Lock()
    defer m.Unlock()
    c.value++
    wg.Done()
    } copies lock value: sync.Mutex
    ./prog.go:53:25: func passes lock by value: sync.Mutex
    Go vet exited.

    数数:1000

    play.go
    gramyang
        2
    gramyang  
    OP
       2019-07-08 13:51:25 +08:00
    @Maboroshii 不行
    gramyang
        3
    gramyang  
    OP
       2019-07-08 14:00:00 +08:00
    @Maboroshii 把锁换成指针传递后可以了。。。。。
    Maboroshii
        4
    Maboroshii  
       2019-07-08 14:01:23 +08:00
    @gramyang #2

    type counter struct {
    sync.Mutex
    value int
    }

    func test2() {
    runtime.GOMAXPROCS(1)
    var wg sync.WaitGroup
    wg.Add(1000)
    c := new(counter)
    c.value=0
    for i := 0; i < 1000; i++ {
    go func(c *counter) {
    c.Lock()
    defer c.Unlock()
    c.value++
    wg.Done()
    }(c)
    }
    wg.Wait()
    fmt.Println("数数:", c.value)
    }

    func main() {
    test2()
    }
    xeaglex
        5
    xeaglex  
       2019-07-08 17:18:14 +08:00
    [官方文档]( https://godoc.org/sync) 第一段话说了:

    > Values containing the types defined in this package should not be copied.
    pubby
        6
    pubby  
       2019-07-08 18:06:24 +08:00
    想起了以前偷懒这样写

    client := &http.Client{}
    t := *( http.DefaultTransport.(*http.Transport))
    t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
    client.Transport = http.RoundTripper(&t)

    结果高并发时 http 内部锁随机炸
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2837 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 07:27 · PVG 15:27 · LAX 23:27 · JFK 02:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.