目录

go高并发下全局自增的实现

1.使用互斥锁mutex

定义一个struct,结构体中含有可计数的变量,并嵌入sync.Mutex,使对象具有加锁和解锁的能力,每次对对象进行加操作的时候先进行加锁,计算结束后再进行解锁

 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
package main

import (
	"fmt"
	"sync"
)


var wg sync.WaitGroup

type SafeCounter struct {
	v map[string]int
	mutex sync.Mutex
}

func (c *SafeCounter)Inc(key string){
	c.mutex.Lock()
	c.v[key]++
	c.mutex.Unlock()
	wg.Done()
}

func(c *SafeCounter)Value(key string) int{
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return c.v[key]
}

func main() {
	counter := SafeCounter{
		v:     make(map[string]int),
	}
	for i:=0;i<999999;i++{
		wg.Add(1)
		go counter.Inc("mykey")
	}

	wg.Wait()

	fmt.Println(counter.Value("mykey"))
}

2.使用 atomic 包,执行原子操作

使用atomic包,可以对int进行原子操作,其背后使用的是汇编语言实现的

 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
package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

var wg sync.WaitGroup

var SafeCounter int64

func Inc() {
	atomic.AddInt64(&SafeCounter, 1)
	wg.Done()
}

func Value() int64 {
	return SafeCounter
}

func main() {

	for i := 0; i < 999999; i++ {
		wg.Add(1)
		go Inc()
	}

	wg.Wait()

	fmt.Println(Value())
}

3.使用CSP模型

创建一个长度为1的channel,用单个goroutine循环等待常驻监听channel传过来的值,并进行消费。通过channel保证了对全局变量的单线程操作

 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
package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

var SafeCounter int64

func Inc(c chan int64) {
    //常驻监听
	for{
		select {
		case v:= <-c:
			SafeCounter += v
		}
	}
}

func Value() int64 {
	return SafeCounter
}

func main() {

	c := make(chan int64)
	go Inc(c)

	for i := 0; i < 999999; i++ {
		wg.Add(1)
		go func() {
			c <-1
			wg.Done()
		}()
	}
	
	wg.Wait()
	fmt.Println(Value())
}