Don’t communicate by sharing memory; share memory by communicating.
라길래, channel과 mutex의 성능을 알아봤다.
테스트 머신은 Xeon CPU가 두 개 달렸고, 12G의 램을 가지고 있다. 각 CPU당 6개의 코어가 있으므로, 하이퍼쓰레딩을 이용하여 최대 24개의 코어를 사용할 수 있다.
테스트는 channel을 사용하는 경우와 mutex를 사용하는 경우로 나눴으며, 10번의 결과를 평균내어 최종 결론을 만든다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
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 benchMessage(clientNum int) time.Duration { sharedValue := 0 var wg sync.WaitGroup start := time.Now() reqChan := make(chan Request, 100) 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) } wg.Wait() elapsed := time.Since(start) return elapsed } func benchMutex(clientNum int) time.Duration { sharedValue := 0 var wg sync.WaitGroup start := time.Now() 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) return elapsed } func main() { clientNum := flag.Int("client", 500000, "Number of clients") repeatCount := flag.Int("repeat", 10, "Repeat count") flag.Parse() rand.Seed(time.Now().UnixNano()) cores := [...]int{1, 2, 4, 8, 16} for _, coreNum := range cores { runtime.GOMAXPROCS(coreNum) var messageTotalElapsed time.Duration var mutexTotalElapsed time.Duration for i := 0; i < *repeatCount; i++ { messageTotalElapsed += benchMessage(*clientNum) mutexTotalElapsed += benchMutex(*clientNum) } fmt.Println("cores:", coreNum, "message:", messageTotalElapsed/time.Duration(*repeatCount), "mutex:", mutexTotalElapsed/time.Duration(*repeatCount)) } } |
아래의 그래프가 그 결과로, 사용하는 코어의 개수와 관계없이 channel을 사용하는 것이 mutex를 사용하는 것보다 느리다는 것을 알려준다.
추가로 테스트 한 바, channel의 크기를 변경하는 것은 결과에 별다른 영향을 미치지 못한다.
Go로 프로그래밍 할 경우, channel을 사용할지 mutex를 사용할지에 대한 조언은 여기에 좀 더 자세히 나와있다.