协程
package main
import "time"
func main() {
go say("Hello World")
// 没有下一行,则主线程都结束了协程还没打印完说不定
time.Sleep(time.Second * 1)
}
func say(s string) {
println(s)
}
2.WaitGroup
package main
import (
"sync"
)
// 协程队列
var wg = sync.WaitGroup{
}
func main() {
// 加入队列
wg.Add(1)
go say("Hello World")
// 告诉主线程等一下,等协程都执行完了在退出
wg.Wait()
}
func say(s string) {
println(s)
// 协程处理完毕 相当于 wg.Add(-1)
wg.Done()
}
同时启动多个协程的时候
package main
import (
"strconv"
"sync"
)
// 协程队列
var wg = sync.WaitGroup{
}
func main() {
// 加入队列
wg.Add(5)
for i := 0; i < 5; i++ {
go say("Hello World" + strconv.Itoa(i))
}
// 告诉主线程等一下,等协程都执行完了在退出
wg.Wait()
}
func say(s string) {
println(s)
// 协程处理完毕
wg.Done()
}
看上去像是“同时执行”,其实这只是并发
并发 并行 核心数量
并发:单核CPU。同一时间只能执行一个程序,但是CPU却可以在不同程序之间快速切换
并行:多核CPU。CPU分别处理不同程序,一起执行。
// 设置核心数,模拟单核
runtime.GOMAXPROCS(1)
对于 n 个核心的情况设置 GOMAXPROCS 为 n-1 以获得最佳性能,也同样需要遵守这条规则:协程的数量 > 1 + GOMAXPROCS > 1。
用命令行指定使用的核心数量
使用 flags 包,如下:
var numCores = flag.Int("n", 2, "number of CPU cores to use")
在 main() 中:
flag.Parse()
runtime.GOMAXPROCS(*numCores)
channel
协程之间通信的渠道,消息队列
数据在通道中进行传递:在任何给定时间,一个数据被设计为只有一个协程可以对其访问,所以不会发生数据竞争。 数据的所有权(可以读写数据的能力)也因此被传递。
通常使用这样的格式来声明通道:var identifier chan datatype
- 未初始化的通道的值是nil。
- 只能传输一种类型的数据,比如 chan int 或者 chan string,所有的类型都可以用于通道,空接口 interface{}也可以。甚至可以(有时非常有用)创建通道的通道。
- 引用类型,使用make创建
- 先进先出(FIFO)的结构保证顺序
<-
流向通道
ch <- int1
从通道流出(三种)
int2 := <- ch int2未声明
int3 = <- ch int3已声明
// 单独调用获取通道的(下一个)值,当前值会被丢弃,但是可以用来验证
if <- ch == 200 {
}
Eg:
package main
import (
"fmt"
"time"
)
func main() {
var ch = make(chan string)
go add(ch)
go delete(ch)
time.Sleep(time.Second * 1)
}
func add(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
}
func delete(ch chan string) {
var c string
for {
c = <- ch
fmt.Println(c)
}
}
通道阻塞
需求,把输出结果返回给主线程:
package main
import "strconv"
func main() {
var result = make(chan string)
for i