并发concurrency
从源码的解析来看,goroutine 只是由官方实现的超级“线程池”而已。
不过话说回来,每个实例 4-5KB 的栈内存占用和由于实现机制而大幅
减少的创建和销毁开销,是制造 Go 号称的高并发的根本原因。另外,
goroutine 的简单易用,也在语言层面上给予了开发者巨大的便利。
并发不是并行:Concurrency Is Not Parallelism
并发主要由切换时间片来实现“同时”运行,在并行则是直接利用
多核实现多线程的运行,但 Go 可以设置使用核数,以发挥多核计算机
的能力。
Goroutine 奉行通过通信来共享内存,而不是共享内存来通信。
Channel
Channel 是 goroutine 沟通的桥梁,大都是阻塞同步的
通过 make 创建,close 关闭
Channel 是引用类型
可以使用 for range 来迭代不断操作 channel
可以设置单向或双向通道
可以设置缓存大小,在未被填满前不会发生阻塞
简单示例 Channel的基本操作
package main
import (
"fmt"
)
func main() {
//创建channel
c := make(chan bool)
//匿名函数 闭包
go func() {
fmt.Println("Go Go Go !!!!")
//执行存的操作,设置Channel为true
c <- true
}()
// 取出来
<-c
}
通过for range迭代来控制Channel通信
func main() {
//创建channel
c := make(chan bool)
//匿名函数 闭包
go func() {
fmt.Println("Go Go Go !!!!")
//执行存的操作,设置Channel为true
c <- true
close(c)
}()
//当Channel有值的时候打印出来,close后,迭代结束
for v := range c {
fmt.Println(v)
}
}
多核并发 示例一
package main
import (
"fmt"
"runtime"
)
func main() {
//设置多核运行
runtime.GOMAXPROCS(runtime.NumCPU())
//创建Channel
c := make(chan bool, 10)
//运行10个goroutine
for i := 0; i < 10; i++ {
go Go(c, i)
<-c
}
}
func Go(c chan bool, index int) {
a := 1
for i := 0; i < 100000000; i++ {
a += i
}
fmt.Println(index, a)
//存入true
c <- true
}
多核并发,通过sync.WaitGroup 示例二
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
//设置多核运行
runtime.GOMAXPROCS(runtime.NumCPU())
//waigroup解决方案
wg := sync.WaitGroup{}
//添加10个任务组
wg.Add(10)
//运行10个goroutine
for i := 0; i < 10; i++ {
go Go(&wg, i)
}
//等待
wg.Wait()
}
func Go(wg *sync.WaitGroup, index int) {
a := 1
for i := 0; i < 100000000; i++ {
a += i
}
fmt.Println(index, a)
//结束
wg.Done()
}
select发射和接收
package main
import (
"fmt"
)
func main() {
//创建 两个Channel
c1, c2 := make(chan int), make(chan string)
//添加一个Channel用来作标记,
o := make(chan bool)
//匿名函数,闭包
go func() {
//无限循环,实现不断的信息接收和发送工作
for {
//类似switch
select {
//v是局部变量,不会冲突,取出c1的值
case v, ok := <-c1:
//当不存在ok
if !ok {
//写入标记
o <- true
break
}
//如果v存在
fmt.Println("c1", v)
//v是局部变量,不会冲突,取出c1的值
case v, ok := <-c2:
//当不存在ok
if !ok {
//写入标记
o <- true
break
}
//如果v存在
fmt.Println("c2", v)
}
}
}()
//存入值
c1 <- 1
c2 <- "hi"
c1 <- 3
c2 <- "hello"
//关闭
close(c1)
close(c2)
//读取标记
for i := 0; i < 2; i++ {
<-o
}
}
select 设置超时
package main
import (
"fmt"
"time"
)
func main() {
//创建Channel
c := make(chan bool)
select {
case v := <-c:
fmt.Println(v)
//3秒后,输出超时
case <-time.After(3 * time.Second):
fmt.Println("Timeout")
}
}