我已经完成了简单的基准测试,其中一个在消息传递和锁定共享值方面更有效.
首先,请检查下面的代码.
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)
}
Run Code Online (Sandbox Code Playgroud)
正如您已经注意到的,程序相对简单.在消息模式下,它通过消息传递增加sharedValue.在互斥模式下,它通过锁定增加sharedValue.
我试图只使用一个频道进行消息模式并放弃了.我想这可能不可能,不是吗?
我的电脑有2个Xeon CPU,每个都有6个核心.由于超线程,逻辑上可以使用24个内核.它的公羊尺寸是12G.
如果我使用任何数字运行程序的标志,互斥模式总是最快2倍(通常是3次).
好的,我可以理解管理渠道需要一定的成本.那么,如果我只考虑性能,有没有理由使用channel而不是mutex?另外,消息传递成本可以被巨大的消息大小忽略吗?
如果我只考虑性能,有没有理由使用频道而不是互斥?
并不是的.维基页面" 使用一个sync.Mutex或一个频道? "说要使用最具表现力和/或最简单的那个.
有一个用于Mutex的频道示例,但评论如下:
虽然通道为受保护的数据提供了一个很好的解决方案,但对于一个作者和许多读者而言,它是一种效率较低的解决方案
这个主题增加了:
如果您正在共享数据,并且永远不会在锁定部分中阻塞,请使用互斥锁.
在非阻塞情况下,互斥锁真的很便宜.如果你有一些复杂或冗长的共享服务,并且必须进行序列化,请考虑给它自己的goroutine,它接收来自通道的请求并在完成时发回回复.通常你发送一个
struct带有输入参数和一个用于回复的通道对象.
这很像RPC.通道用于通信,而不是锁定.
如果您通过通道发送无意义的数据仅用于锁定目的,那么您可能会过度复杂化.