编程语言20、并发状态-GOLANG
xiu多个goroutine有可能出现使用同一个值的场景,这种情况被称为竞态条件,有可能造成程序报错,两个goroutine同时读取一个相同的事物不会造成竞态条件,只有当一方在写入,另一方无论进行读取还是写入的时候才会产生竞态条件
互斥锁
mutex,互斥锁提供了Lock和Unlock两个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package main
import "sync"
type Visited struct { mu sync.Mutex visited map[string]int }
func (v Visited) VisitedLink(url string) int { v.mu.Lock() defer v.mu.Unlock() count := v.visited[url] count++ v.visited[url] = count return count } func main() {
}
|
隐患
如果一个goroutine在锁定互斥锁之后被阻塞了,想要获取这个数值的其它goroutine纪要等待相当长的一段时间。更严重的是如果持有互斥锁的goroutine尝试锁定同一个互斥锁,那么就会引发死锁
长时间运行的工作机制
场景描述,利用goroutine实现一台好奇号火星探测器的各个模块,用于探索一个虚假的火星,我们将对探测器坐标的变量进行更新,并且还需要探测器对外部的命令进行响应
第一步,我们需要启动一个goroutine负责探测好奇号的位置,这个goroutine会随着探测器软件一同启动,直到被关闭,这种一直存在并且独立运行的goroutine称为工作进程(worker),工作进程通常被携程包含select语句的for循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| package main
import ( "fmt" "image" "log" "time" )
type command int
const ( right = command(0) left = command(1) )
type RoverDriver struct { commandc chan command }
func NewRoverDriver() *RoverDriver { r := &RoverDriver{ commandc: make(chan command), } go r.drive() return r } func (r *RoverDriver) drive() { pos := image.Point{0, 0} direction := image.Point{1, 0} updateInterval := 250 * time.Millisecond nextMove := time.After(updateInterval) for { select { case c := <-r.commandc: switch c { case right: direction = image.Point{-direction.Y, direction.Y} case left: direction = image.Point{direction.Y, -direction.X} } log.Printf("new direction %v", direction) case <-nextMove: pos = pos.Add(direction) log.Printf("Move to%v", pos) nextMove = time.After(updateInterval)
} } } func (r *RoverDriver) Left() { r.commandc <- left } func (r *RoverDriver) Right() { r.commandc <- right }
func worker() { pos := image.Point{10, 10} direction := image.Point{1, 0} next := time.After(time.Second) for { select { case <-next: pos = pos.Add(direction) fmt.Println("current position is", pos) next = time.After(time.Second) } } } func main() { r := NewRoverDriver() time.Sleep(3 * time.Second) r.Left() time.Sleep(3 * time.Second) r.Right() time.Sleep(3 * time.Second) }
|