并发编程
并发 多线程程序在一个核的CPU上运行 并行 多线程程序在多个核的CPU上运行
Go有高效的调度模型, 可以充分发挥多核优势, 高效运行
Goroutine
协程: 用户态, 轻量级线程, 栈KB级别 线程: 内核态, 线程跑多个协程, 栈MB级别
package main
import (
"strconv"
"time"
)
func main() {
for i := 0; i < 5; i++ {
go func(i int) {
println("hello goroutine: " + strconv.Itoa(i))
}(i)
}
time.Sleep(time.Second)
}
CSP(Communicating Sequential Processes)
提倡通过通信共享内存而不是通过共享内存而实现通信
Channel
make(chan 元素类型, [缓冲大小])
- 无缓冲管道(同步通道)
make(chan int) - 有缓冲管道
make(chan int, 2)
eg: A协程发送数字 0 ~ 9, B协程计算数字的平方, 主协程输出计算结果
带缓冲的channel可以缓解生产者消费者速度不匹配的问题
package main
import (
"fmt"
"time"
)
func main() {
src := make(chan int)
desc := make(chan int)
go func() {
defer close(src)
// 生产
for i := 0; i < 10; i++ {
src <- i
time.Sleep(500 * time.Millisecond)
}
}()
go func() {
defer close(desc)
// 消费并生产
for v := range src {
desc <- v * v
}
}()
// 消费
for v := range desc {
fmt.Println(v)
}
}
并发安全 Lock
package main
import (
"fmt"
"sync"
"time"
)
var x int64
var lock sync.Mutex
func addWithLock() {
for i := 0; i < 100000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 100000; i++ {
x += 1
}
}
func main() {
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
fmt.Println(x)
x = 0
for i := 0; i < 5; i++ {
go addWithLock()
}
time.Sleep(time.Second)
fmt.Println(x)
}
WaitGroup
通过sleep强制阻塞固定时间, 不够优雅, 可以使用WaitGroup实现同步
package main
import (
"fmt"
"sync"
)
var x int64
var lock sync.Mutex
var wg sync.WaitGroup
func addWithLock() {
defer wg.Done()
for i := 0; i < 100000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
defer wg.Done()
for i := 0; i < 100000; i++ {
x += 1
}
}
func main() {
wg.Add(5)
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
wg.Wait()
fmt.Println(x)
wg.Add(5)
x = 0
for i := 0; i < 5; i++ {
go addWithLock()
}
wg.Wait()
fmt.Println(x)
}