go并发获取数据
go语言可以很轻松的实现并发获取数据,就算是新手也可以按部就班的套用现成的并发模式来实现并发。以下是一个简单的测试程序,其中有串行,并行。
package main
import (
"sync"
"time"
"fmt"
)
func main() {
syncFunc()
fmt.Println(">>>>>>>>>>>>>>>")
asyncFunc()
fmt.Println(">>>>>>>>>>>>>>>")
asyncChanFunc()
}
// 串行执行
func syncFunc() {
var n,m,x int
start := time.Now()
fmt.Println("syncFunc start:",start)
func () {
time.Sleep(time.Second*1)
n = 1
}()
func () {
time.Sleep(time.Second*2)
m = 2
}()
func () {
time.Sleep(time.Second*3)
x =3
}()
t := time.Now()
fmt.Println(t)
elapsed := t.Sub(start)
fmt.Println("syncFunc end:", elapsed, n, m, x)
}
// 并行执行
func asyncFunc() {
var n,m,x int
var wg sync.WaitGroup
wg.Add(3)
start := time.Now()
fmt.Println("asyncFunc start:", start)
go func () {
defer wg.Done()
time.Sleep(time.Second*1)
n = 1
}()
go func () {
defer wg.Done()
time.Sleep(time.Second*2)
m = 2
}()
go func () {
defer wg.Done()
time.Sleep(time.Second*3)
x = 3
}()
wg.Wait()
t := time.Now()
fmt.Println(t)
elapsed := t.Sub(start)
fmt.Println("asyncFunc end:", elapsed, n, m, x)
}
// 并行执行
func asyncChanFunc() {
var n, m, x =make(chan int),make(chan int),make(chan int)
start := time.Now()
fmt.Println("asyncChanFunc start:",start)
go func () {
time.Sleep(time.Second*1)
n <- 1
}()
go func () {
time.Sleep(time.Second*2)
m <- 2
}()
go func () {
time.Sleep(time.Second*3)
x <- 3
}()
fmt.Printf("n:%d, m:%d, x:%d\n",<-n, <-m, <-x)
t := time.Now()
fmt.Println(t)
elapsed := t.Sub(start)
fmt.Println("asyncChanFunc end:", elapsed)
}
测试结果:
看完代码和执行结果再来详细说明一下,time.Sleep(time.Second*1)
是用来模拟该段程序需要执行n秒,syncFunc
函数是串行的,耗时6秒。asyncFunc
和asyncChanFunc
是并行的。耗时近乎3秒。而这两种模式略有不同,
** asyncFunc
使用了sync.WaitGroup
**
Add添加了3个goroutine Done是每一个goroutine执行完减1 Wait是阻塞上面的代码,只有当WaitGroup中的goroutine数量为0才往下执行 这种模式算是很简单直观的实现了并行。
** asyncChanFunc
则是使用了chanel来实现并发**
可以看到程序中有fmt.Printf("n:%d, m:%d, x:%d\n",<-n, <-m, <-x)
这段代码,目的是用来阻塞程序,如果n, m, x中没有写入数据,<-n, <-m, <-x
不能读取到数据就会一直阻塞。
如果没有线程间的数据通信的话使用asyncFunc
即可,chanel适用于更复杂的场景。