go语言sync.WaitGroup

来源:互联网 发布:四分位数java 编辑:程序博客网 时间:2024/05/21 10:04

一句话总结:sync.WaitGroup用于等待一个系列执行完成,不能保证数据的原子性操作。

go语言中有两种同步机制,一种是channel,另一种是锁机制。sync.WaitGroup是一种比较简单的同步机制,接口简洁只有三个,Add(),Done(),Wait();其中Add()是添加计数,Done()是减去一个计数,本质是Add(-1),Wait是阻塞等待计数为0;

// Done decrements the WaitGroup counter.
func (wg *WaitGroup) Done() {
wg.Add(-1)
}


看一个没有同步的例子,很明显计数最后没有达到10

package main
import (
"fmt"
_ "sync"
_ "time"
)
var g_cnt int = 0
func main() {
for i := 0; i < 10; i++ {
go func(i int) {
g_cnt++
fmt.Println("i:", i)
}(i)
}
fmt.Println("g_cnt:", g_cnt)
}

结果:

g_cnt: 2

i: 0

i: 5

i: 2

i: 1

成功: 进程退出代码 0.


很明显主进程退出,goroutine没有全部执行完成就终止了。


package main
import (
"fmt"
_ "sync"
"time"
)
var g_cnt int = 0
func main() {
for i := 0; i < 1000; i++ {
go func(i int) {
g_cnt++
fmt.Println("i:", i)
}(i)
}
time.Sleep(10 * time.Second)
fmt.Println("g_cnt:", g_cnt)
}

结果:

...........

i: 994

i: 989

i: 990

i: 995

i: 991

i: 999

i: 997

i: 985

i: 947

i: 998

g_cnt: 990

成功: 进程退出代码 0.


加了10s延时后所有goroutine都运行结束,由于没有同步机制,最后基数没有到达1000.


package main
import (
"fmt"
"sync"
_ "time"
)
var g_cnt int = 0
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
go func(i int) {
wg.Add(1)
defer wg.Done()
g_cnt++
fmt.Println("i:", i)
}(i)
}
wg.Wait()

结果:

.........

i: 977

i: 991

i: 983

i: 996

i: 992

i: 984

i: 993

i: 997

i: 982

i: 998

g_cnt: 996

成功: 进程退出代码 0.


可以看出,waitgroup只是保证了所有goroutine执行结束,从字面上看WaitGroup就是指等待一组,等待一个系列执行完成后才会继续向下执行。所有不能保证数据的原子性操作。

package main
import (
"fmt"
"sync"
_ "time"
)
var g_cnt int = 0
func main() {
var wg sync.WaitGroup
var mutex sync.RWMutex
for i := 0; i < 1000; i++ {
go func(i int) {
wg.Add(1)
defer wg.Done()
mutex.Lock()
defer mutex.Unlock()
g_cnt++
fmt.Println("i:", i)
}(i)
}
wg.Wait()
fmt.Println("g_cnt:", g_cnt)
}

结果:

......

: 988

i: 995

i: 540

i: 996

i: 990

i: 997

i: 991

g_cnt: 1000

成功: 进程退出代码 0.


结果读写锁后发现每次结果都是1000.








原创粉丝点击