您的位置:首页 > 编程语言 > Go语言

简单看懂GO语言并发

2017-08-03 00:00 489 查看

并发基础

GO语言处理并发非常简单,使用关键词“go”即可。

创建main.go文件,内容如下:

package main

func main() {
go print(1)
}

这是一个非常简单的并发例子。运行 go run main.go,你会发现什么也不会输出。为什么?因为没等print执行,主程就退了。

我们把代码修改下:

package main

import "time"

func main() {
go print(1)
time.Sleep(time.Second)
}

这里停了一秒,使得print有足够的时间输出后结束。假设print执行超过一秒钟,或者我们压根不知道print要执行多少时间,这是后我们就要要到“channel”啦。

package main

import (
"fmt"
"time"
)

func main() {
done := make(chan bool)
go Print(1, done)
for {
<-done
break
}
}

func Print(args interface{}, done chan bool) {
time.Sleep(time.Second * 3)
fmt.Println(args)
done <- true
}

无论我们怎么调整sleep的参数,程序都会等待print输出后才结束。到这里我们想如果Print 3秒钟后还没执行我们就要退出了,这里就可以用到channel的一个超时处理方式:

package main

import (
"fmt"
"time"
)

func main() {
done := make(chan bool)
isTimeOut := make(chan bool)
go Print(1, done)
go func(){
time.Sleep(time.Second*3)
isTimeOut <- true
}()
for {
select {
case <-done:
return
case <-isTimeOut:
println("timeout.")
return
}
}
}

func Print(args interface{}, done chan bool) {
time.Sleep(time.Second * 5)
fmt.Println(args)
done <- true
}

这里go run main.go输出"timeout."。我们可以设置缓冲,如:

result := make(chan int,10)

result一开始会存入10个元素,阻塞直到result的元素被取出且小于10后才能再往result写入数据。

并发应用

使用go并发我们可以进行任务分发:

package main

import (
"fmt"
)

func main() {
result := make(chan int)
rlt := 0
go Sum(1, 50, result)
go Sum(51, 100, result)
//把两次写入到result的值取出来求和
for i := 1; i <= 2; i++ {
rlt += <-result
}
fmt.Println(rlt)
}

func Sum(start, end int, result chan int) {
sum := 0
for i := start; i <= end; i++ {
sum += i
}
result <- sum
}

这里计算1+2+3+..+100的和,并发两个进程处理。当然这里为了演示不考虑算法问题了。

使用GO并发构建工作池,工作池就是能进行特定功能处理的“工人”的集合。这里的“工人”可以理解为我们封装好的函数比如上面sum。看下简单的一个示例:

package main

import (
"fmt"
)

func main() {
start, end := make(chan int), make(chan int)
//启动有五个工人的工作池
for i := 0; i <= 4; i++ {
go Sum(i, start, end)
}
//发送任务给工作池中工人处理
for i := 1; i <= 5; i++ {
start <- i * 5
end <- i * 10
}
}

func Sum(worker int, start, end chan int) {
sum := 0
s := <-start
e := <-end
for i := s; i <= e; i++ {
sum += i
}
fmt.Println("worker ", worker, " -> ", sum)
}

每次go run main.go输出的顺序,结果可能都不一样:

worker  4  ->  45
worker  2  ->  360
worker  1  ->  165
worker  3  ->  630
worker  0  ->  975

worker  4  ->  45
worker  1  ->  165
worker  3  ->  360
worker  0  ->  630
worker  2  ->  975

可以看出,只要哪个“工人”通道中获取到需要计算的值,谁就先处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Go并发