编程语言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) }
 
   |