我是靠谱客的博主 认真鱼,这篇文章主要介绍golang学习笔记之并发优化(二),现在分享给大家,希望可以做个参考。

打包发送

通往管道的数据如果一次打包发送的性能要高于多次发送。请看下面里面,这个里面我往管道里面发送50000000次

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func main() { done ,c :=make(chan int),make(chan int ,500) go func() { count :=0 for x := range c { count +=x } close(done) }() for i :=0 ;i<50000000;i++{ c<-i } close(c) <- done }

结果如下:
time go run mutilsend.go
1249999975000000

real 0m4.705s
user 0m6.666s
sys 0m1.319s

而当我使用数组打包发送,如下:

复制代码
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
package main func main() { done ,c :=make(chan int),make(chan [500]int ,500) flag :=0 send :=[500]int{} go func() { count :=0 for x := range c { for _,y :=range x { count +=y } } println(count) close(done) }() for i :=0 ;i<50000000;i++{ send[flag] = i if flag ==499 { flag=0 c<-send }else{ flag +=1 } } close(c) <- done }

结果是:
time go run mutilsend.go
1249999975000000

real 0m0.209s
user 0m0.244s
sys 0m0.053s
效率得到了很大的提升。建议搭建在数据量比较大的时候打包发送数据。

锁复制

无论是哪种编程语言,锁对象一定得是公用的,所以的协程是应为共享同一个锁而导致阻塞的,这一点非常重要,下面演示结构体里面使用锁,直接使用会产生锁复制

复制代码
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
import ( "sync" "time" ) type person struct { sync.Mutex } func (p person) test(act string) { p.Lock() defer p.Unlock() for i:=1;i<10; i++ { println(act,i) time.Sleep(time.Millisecond*100) } } func main() { var p person var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() p.test("read") }() go func() { defer wg.Done() p.test("write") }() wg.Wait() }

结果如下:
write 1
read 1
read 2
write 2
write 3
read 3
read 4
write 4
read 5
write 5
write 6
read 6
write 7
read 7
read 8
write 8
write 9
read 9
在write的方法没有释放之前,read就使用了这个test,test这个应该函数是不能被其它地方使用的,这里面问题就在锁复制,如何解决这个问题呢,很简单,指针应用

复制代码
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
package main import ( "sync" "time" ) type person struct { sync.Mutex } func (p *person) test(act string) { p.Lock() defer p.Unlock() for i:=1;i<10; i++ { println(act,i) time.Sleep(time.Millisecond*100) } } func main() { var p =new(person) var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() p.test("read") }() go func() { defer wg.Done() p.test("write") }() wg.Wait() }

这个里面通过指针的方式避免lock 复制,大家共享同一个锁,看结果
write 1
write 2
write 3
write 4
write 5
write 6
write 7
write 8
write 9
read 1
read 2
read 3
read 4
read 5
read 6
read 7
read 8
read 9
我再上面每次打印睡眠是为了掩饰效果,如果不睡眠,很快执行完毕,很难看到效果。

锁粒度

在加锁的时候请保持一个原则,最小的锁粒度,在能控制的情况下,尽早的释放锁。
譬如上面的例子

复制代码
1
2
3
4
5
6
7
8
func (p *person) test(act string) { p.Lock() defer p.Unlock() for i:=1;i<10; i++ { println(act,i) time.Sleep(time.Millisecond*100) } }

这里的defer是对整个函数加锁,如果这里设计到多个操作,都在锁范围,如果这里多个操作,有的并不需要加锁,可以减少,如

复制代码
1
2
3
4
5
6
func (p *person) test(act string) { d =curl x.x.x.x p.Lock() date[i] = d p.Unlock() }

上面的请求就没必要加锁,这个在多个调用的时候可以减少等待时间。

死锁

死锁简单的说就是:你等我,我等你。在golang里面重复的加锁也会导致死锁,看下面例子:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main import "sync" func main() { println("start") var m sync.Mutex m.Lock() m.Lock() m.Unlock() m.Unlock() println("end") }

结果如下:
start
fatal error: all goroutines are asleep - deadlock!
死锁了!

最后

以上就是认真鱼最近收集整理的关于golang学习笔记之并发优化(二)的全部内容,更多相关golang学习笔记之并发优化(二)内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部