携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
Go 并发
- 并发: 逻辑上同时处理多个任务的能力
- 并行:物理行通一个时刻执行多个并发任务
多线程和多进程是并行的基本条件,但是单线程可以用到协程(coroutine)做到并发,尽管协程在单线程上是通过主动切换来实现多任务并发。
- 用多进程来实现分布式和负载均衡,减轻单进程垃圾回收带来的压力
- 用多线程来抢夺更多的处理器资源,
- 用协程来提高处理器的时间片利用率
简单的 goroutine 归纳为协程并不合适, 运行时会创建多个线程来执行任务,任务单元调度到其他线程并行执行
只需要在函数前 添加 go 关键字即可创建并发任务
package main
import (
"fmt"
"time"
)
var c int
func counter() int {
c++
return c
}
func main() {
a := 100
go func(x, y int) {
time.Sleep(time.Second)
fmt.Println("go:", x, y)
}(a, counter())
a += 100
fmt.Println("main:", a, counter())
time.Sleep(time.Second *3)
}
运行结果
main: 200 2
go: 100 1
Process finished with exit code 0
Wait
进程退出时,不会等待并发任务结束,可用通道(channel)阻塞,然后发出退出信号。
package main
import (
"fmt"
)
func Add(a, b int){
z := a + b
fmt.Println("z:",z)
}
func main() {
for i := 0; i < 10; i++ {
go Add(i,i)
}
//time.Sleep(time.Second * 1000) // 没有这一行会发现什么都没有,因为主线程不等待其他 goroutine 结束
}
工程上常见的并发通信模型: 共享数据和消息
不要通过共享内存来通信,要通过通信来共享内存
channel
channel 是 Go 语言提供的 goroutine 间的通信方式, 我们可以使用 channel 在两个或者多个 goroutine 之间进行消息传递, channel 是进程内的通信方式, 因此,通过 channel 对象传递的过程和调用函数时传递的参数行为比较一致,比如也可以传递指针。
channel 是类型相关的,也就是说, 一个 channel 只能传递一种类型的值, 这个类型需要在声明 channel 时指定,
package main
import "fmt"
func Add(a, b int, ch chan int) {
fmt.Println("Counting")
ch <- a+b
}
func main() {
chs := make([]chan int, 10)
for i :=0; i < 10; i++ {
chs[i] = make(chan int)
go Add(i, i, chs[i])
}
for _, ch := range chs {
val := <- ch
fmt.Println(val)
}
}
执行结果
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
0
2
Counting
4
6
8
10
12
14
16
18