## sync.WaitGroup
WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。
这里要注意一下,他们的执行结果是没有顺序的,调度器不能保证多个 goroutine 执行次序,且进程退出时不会等待它们结束。
WaitGroup总共有三个方法:Add(delta int),Done(),Wait()。简单的说一下这三个方法的作用。
Add:添加或者减少等待goroutine的数量
Done:相当于Add(-1)
Wait:执行阻塞,直到所有的WaitGroup数量变成0
如:
```
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0; i > 5; i = i + 1 {
wg.Add(1)
go func(n int) {
// defer wg.Done(),注意这个Done的位置,是另一个函数
defer wg.Add(-1)
EchoNumber(n)
}(i)
}
wg.Wait()
}
func EchoNumber(i int) {
time.Sleep(3e9)
fmt.Println(i)
}
```
golang中的同步是通过sync.WaitGroup来实现的.WaitGroup的功能:它实现了一个类似队列的结构,可以一直向队列中添加任务,当任务完成后便从队列中删除,如果队列中的任务没有完全完成,可以通过Wait()函数来出发阻塞,防止程序继续进行,直到所有的队列任务都完成为止.
WaitGroup的特点是Wait()可以用来阻塞直到队列中的所有任务都完成时才解除阻塞,而不需要sleep一个固定的时间来等待.但是其缺点是无法指定固定的goroutine数目.可能通过使用channel解决此问题。
另一个例子:
```
package main
import (
"fmt"
"sync"
)
//声明一个全局变量
var waitgroup sync.WaitGroup
func Afunction(shownum int) {
fmt.Println(shownum)
waitgroup.Done() //任务完成,将任务队列中的任务数量-1,其实.Done就是.Add(-1)
}
func main() {
for i := 0; i < 10; i++ {
waitgroup.Add(1) //每创建一个goroutine,就把任务队列中任务的数量+1
go Afunction(i)
}
waitgroup.Wait() //.Wait()这里会发生阻塞,直到队列中所有的任务结束就会解除阻塞
}
```
## sync.Mutex
golang的多线程固然好用,但是有时候需要对数据进行上锁,防止数据被其它线程更改。那么sync包下的Mutex非常好用。
Mutex是一个互斥锁。可以作为struct的一部分,这样这个struct就会防止被多线程更改数据。
```go
package main
import (
"fmt"
"sync"
"time"
)
type User struct {
Name string
Locker *sync.Mutex
}
func (u *User) SetName(wati *sync.WaitGroup, name string) {
defer func() {
fmt.Println("Unlock set name:", name)
u.Locker.Unlock()
wati.Done()
}()
u.Locker.Lock()
fmt.Println("Lock set name:", name)
time.Sleep(1 * time.Second)
u.Name = name
}
func (u *User) GetName(wati *sync.WaitGroup) {
defer func() {
fmt.Println("Unlock get name:", u.Name)
u.Locker.Unlock()
wati.Done()
}()
u.Locker.Lock()
fmt.Println("Lock get name:", u.Name)
time.Sleep(1 * time.Second)
}
func main() {
user := User{}
user.Locker = new(sync.Mutex)
wait := &sync.WaitGroup{}
names := []string{"a", "b", "c"}
for _, name := range names {
wait.Add(2)
go user.SetName(wait, name)
go user.GetName(wait)
}
wait.Wait()
}
```
- 命令行库cobra
- 用户路径检测go-homedir
- 配置解决方案viper(cobra配置用)
- 高效结构化日志库zap
- RPC框架grpc
- mongdb操作mgo
- ORM库xorm
- GRPCrest接口grpcgateway
- 使用gogoproto时grpcgateway的protobuf和json转换方法
- sync.Map
- zmq
- gogoproto
- go类型转换和类型断言
- go select用法详解以及定时器
- go并发资源竞争
- 官方命令行库flag
- 配置文件解析器 robig/config
- interface {} 接口
- goroutine && channel
- go 命名
- 类型switch
- 数据
- 初始化
- 指针方法 && 值方法
- 内嵌
- mqtt go实现
- grpc middleware