并发执行在Golang中很容易实现,只需要go func(),大多数我们会把一个大的任务拆分成多个子任务去执行,这时候我们就需要关心子任务是否执行成功和结束,需要收到信息进行下一步程序的执行。在golang中,我整理了三种Goroutine常用的控制方式。
1:Sync.WaitGroup:
package main
import (
"context"
"fmt"
"net/http"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
//2个task
wg.Add(2)
go func() {
defer wg.Done()
fmt.Println("goroutine 1 done")
}()
go func() {
defer wg.Done()
fmt.Println("goroutine 2 done")
}()
wg.Wait()
fmt.Println("all goroutine done")
}
2:Channel
package main
import (
"context"
"fmt"
"net/http"
"sync"
"time"
)
func main() {
ch := make(chan int)
flag := make(chan bool)
go son(ch, flag)
for i := 0; i < 10; i++ {
ch <- i
}
flag <- true
fmt.Println("all is over")
}
func son(ch chan int, flag chan bool) {
t := time.Tick(time.Second)
for _ = range t {
select {
case msg := <-ch:
fmt.Println("print", msg)
case <-flag:
fmt.Println("goroutine is over")
}
}
}
使用场景:当一个主任务拆分为子任务去执行,子任务全部执行完毕,通过channel来通知主任务执行完毕,主任务继续向下执行。比较适用于层级比较少的主任务和子任务间的通信。
3:Context
package main
import (
"context"
"fmt"
"net/http"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go foo(ctx, "Sonbar")
fmt.Println("subwork is starting")
time.Sleep(5 * time.Second)
//fiveminutes is over
cancel()
//allgoroutine over
time.Sleep(3 * time.Second)
fmt.Println("main work over")
}
func foo(ctx context.Context, name string) {
go bar(ctx, name)
for {
select {
case <-ctx.Done():
fmt.Println(name, "goroutine A Exit")
return
case <-time.After(1 * time.Second):
fmt.Println(name, "goroutine A do something")
}
}
}
func bar(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "goroutine B Exit")
return
case <-time.After(2 * time.Second):
fmt.Println(name, "goroutine B do something")
}
}
}
使用场景:适用于多层Goroutine嵌套和组合,当然Context包不仅仅用于并发控制,还有更多的功能和场景需要我们去探索。