一尘不染

Golang,如何分享价值-消息还是互斥体?

go

我已经完成了简单的基准测试,在传递消息和锁定共享值方面效率更高。

首先,请检查以下代码。

package main

import (
    "flag"
    "fmt"
    "math/rand"
    "runtime"
    "sync"
    "time"
)

type Request struct {
    Id      int
    ResChan chan Response
}

type Response struct {
    Id    int
    Value int
}

func main() {
    procNum := flag.Int("proc", 1, "Number of processes to use")
    clientNum := flag.Int("client", 1, "Number of clients")
    mode := flag.String("mode", "message", "message or mutex")
    flag.Parse()

    if *procNum > runtime.NumCPU() {
        *procNum = runtime.NumCPU()
    }

    fmt.Println("proc:", *procNum)
    fmt.Println("client:", *clientNum)
    fmt.Println("mode:", *mode)

    runtime.GOMAXPROCS(*procNum)

    rand.Seed(time.Now().UnixNano())
    var wg sync.WaitGroup

    sharedValue := 0

    start := time.Now()

    if *mode == "message" {
        reqChan := make(chan Request) // increasing channel size does not change the result
        go func() {
            for {
                req := <-reqChan
                sharedValue++
                req.ResChan <- Response{Id: req.Id, Value: sharedValue}
            }
        }()

        for i := 0; i < *clientNum; i++ {
            wg.Add(1)
            go func(index int) {
                defer wg.Done()
                c := make(chan Response)
                defer close(c)
                id := rand.Int()
                reqChan <- Request{Id: id, ResChan: c}
                <-c
            }(i)
        }
    } else if *mode == "mutex" {
        mutex := &sync.Mutex{}

        for i := 0; i < *clientNum; i++ {
            wg.Add(1)
            go func(index int) {
                defer wg.Done()
                mutex.Lock()
                sharedValue++
                mutex.Unlock()
            }(i)
        }
    }

    wg.Wait()
    elapsed := time.Since(start)

    fmt.Println("Elapsed:", elapsed, "value:", sharedValue)
}

您已经注意到,程序相对简单。在 消息模式下 ,它通过消息传递来增加sharedValue。在 互斥锁模式下 ,它通过锁定来增加
sharedValue

我尝试只将一个频道用于 消息模式 并放弃了。我认为这不可能,不是吗?

我的计算机有2个Xeon CPU,每个都有6个内核。由于超线程,逻辑上有24个内核可用。它的内存大小是12G。

如果我用任意数量的标志运行程序,则 互斥锁模式 总是至少快2倍(通常是3倍)。

好的,我可以理解,管理渠道需要一定的成本。然后,如果仅考虑性能,是否有任何理由使用通道而不是互斥锁?另外,巨大的消息量可以忽略消息传递成本吗?


阅读 212

收藏
2020-07-02

共1个答案

一尘不染

如果仅考虑性能,是否有任何理由使用通道而不是互斥锁?

并不是的。维基页面“ 使用一个sync.Mutex或一个频道? ”说使用最富表现力和/或最简单的那个。
有一个用于Mutex的通道示例,但已注释如下:

尽管通道为受保护的数据提供了很好的解决方案,但是对于一个作者和许多读者来说,它的效率较低。

该线程添加:

如果您要共享数据,并且从不阻塞锁定部分,请使用互斥锁。
在非阻塞情况下,互斥对象确实很便宜

如果您有一些共享服务执行某些复杂或较长的工作,并且必须对其进行序列化,请考虑为其提供一个自己的goroutine,该例程可接收来自通道的请求并在完成后将回复发送回去。通常,您发送struct带有输入参数的a和用于回复的通道对象。
这很像RPC。

通道用于通信 ,而不是锁定。
如果仅出于锁定目的而通过通道发送无意义的数据,则可能会使事情复杂化。

2020-07-02