Go语言并发之并发实现、多核CPU设置、多协程间的通信、select、多协程间的同步
目录结构
├── gorotine
│ └── gorotine.go
└── main.go
并发实现:协程
启动协程(加go关键字)
gorotine.go文件
package gorotine
import (
"fmt"
"time"
)
func Loop() {
for i:=1;i<11;i++ {
//防止程序运行太快,看不到是否为并发执行,这里暂停10微秒
time.Sleep(time.Microsecond * 10)
fmt.Printf("%d,",i)
}
}
main.go文件
package main
import (
"./gorotine"
"time"
)
func main() {
//调用2次,串行执行
//gorotine.Loop()
//gorotine.Loop()
//运行结果:1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,
//并发,并发执行
go gorotine.Loop()
go gorotine.Loop()
//防止并发运行速度过快,还未在终端输出程序已经结束,这样看不到结果,所以暂停了5秒钟
time.Sleep(time.Second * 5)
//运行结果:1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,
}
多核CPU设置
package main
import (
"./gorotine"
"fmt"
"runtime"
"time"
)
func main() {
//调用2次,串行执行
//gorotine.Loop()
//gorotine.Loop()
//运行结果:1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,
//并发,并发执行
fmt.Printf("cup num = %d", runtime.NumCPU()) // cup num = 12
fmt.Print("\n")
runtime.GOMAXPROCS(runtime.NumCPU() - 1) //限制go程序的运行核心数,一般总核心数减一
go gorotine.Loop() // 加go关键字即可实现协程
go gorotine.Loop()
//防止并发运行速度过快,还未在终端输出程序已经结束,这样看不到结果,所以暂停了5秒钟
time.Sleep(time.Second * 5)
//运行结果:1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,
}
多协程间的通信
channel(管道)
gorotine.go文件
package gorotine
import (
"fmt"
"time"
)
var chanInt chan int = make(chan int, 10) //创建缓存为10的管道
func Send() {//向管道发送数据
time.Sleep(time.Second * 1)
chanInt <- 1
time.Sleep(time.Second * 1)
chanInt <- 2
time.Sleep(time.Second * 1)
chanInt <- 3
}
func Receive() {//获取管道数据
num := <- chanInt
fmt.Println("num:", num)
fmt.Print("\n")
num = <- chanInt
fmt.Println("num:", num)
fmt.Print("\n")
num = <- chanInt
fmt.Println("num:", num)
}
main.go文件
package main
import (
"./gorotine"
"time"
)
func main() {
go gorotine.Send() //启动发送数据的协程
go gorotine.Receive() //启动接收数据的协程
//防止并发运行速度过快,还未在终端输出程序已经结束,这样看不到结果,所以暂停了5秒钟
time.Sleep(time.Second * 5)
//结果:
/*
num: 1
num: 2
num: 3
*/
}
select
gorotine.go文件
package gorotine
import (
"fmt"
"time"
)
var chanInt chan int = make(chan int, 10) //创建缓存为10的管道
var timeout chan bool = make(chan bool) //创建管道
func Send() {//向管道发送数据
time.Sleep(time.Second * 1)
chanInt <- 1
time.Sleep(time.Second * 1)
chanInt <- 2
time.Sleep(time.Second * 1)
chanInt <- 3
time.Sleep(time.Second * 2)
timeout <- true
}
func Receive() {//获取管道数据,同时读取两个文件
for {
select {
case num:=<-chanInt:
fmt.Println("num:", num)
case <-timeout:
fmt.Println("timeout...")
}
}
//应用场景:十个协程读10个不同文件数据往一个协程向文件写数据
}
main.go文件
package main
import (
"./gorotine"
"time"
)
func main() {
go gorotine.Send() //启动发送数据的协程
go gorotine.Receive() //启动接收数据的协程
//防止并发运行速度过快,还未在终端输出程序已经结束,这样看不到结果,所以暂停了5秒钟
time.Sleep(time.Second * 5)
//结果:
/*
num: 1
num: 2
num: 3
timeout...
*/
}
多个协程读取不同文件,写文件的协程把读出来的数据完成后再进行别的操作
)
sync.waitgroup
gorotine.go文件
package gorotine
import (
"fmt"
"sync"
"time"
)
var WG sync.WaitGroup
//读取数据
func Read() {
for i:=0;i<3;i++ {
WG.Add(1) //添加携程记录
}
}
//写入数据
func Write() {
for i:=0;i<3;i++ {
time.Sleep(time.Second * 2)
fmt.Println("Done ->", i)
WG.Done() //移除协程记录
}
}
main.go文件
package main
import (
"fmt"
"time"
"./gorotine"
)
func main() {
gorotine.Read()
go gorotine.Write()
gorotine.WG.Wait()
fmt.Println(" All done!")
//结果:
/*
Done -> 0
Done -> 1
Done -> 2
All done!
*/
time.Sleep(time.Second * 5)
}
下面是拓展(对上面的代码合并一下):
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var arr = []int{1,2,3}
func main() {
for _,val:=range arr{
wg.Add(1) //添加携程记录
go func(val int) {
time.Sleep(time.Second * 10)
fmt.Println("Done ->", val)//执行后续程
defer wg.Done()
}(val)
}
wg.Wait() //移除协程记录
fmt.Println(" All done!") //执行后续程序
}