Skip to content

Go 语言最突出之处是并发编程,Unix 老牌黑客罗勃·派克(Rob Pike)在 Google I/O 上的两个分享,可以让你学习到一些并发编程的模式

goroutine

TODO

Channels

TODO

Synchronization

买票卖票 信号量

Buffered channels

TODO

Generator

返回管道的函数

go
func boring(msg string) <-chan string {
	c := make(chan string)
	go func() {
		for i := 0; ; i++ {
			c <- fmt.Sprintf("%s %d", msg, i)
			time.Sleep(time.Duration(rand.Intn(1e3)) 
				* time.Millisecond)
		}
	}()
	return c
}

Fanin

input1 和 input2 相互独立,有人即使阻塞了,也互不影响

go
func fanIn(input1, input2 <-chan string) <-chan string {
	c := make(chan string)
	go func() {
		for {
			c <- <-input1
		}
	}()
	go func() {
		for {
			c <- <-input2
		}
	}()
	return c
}

使用 select 改造 fanIn

go
func fanIn(input1, input2 <-chan string) <-chan string {
	c := make(chan string)
	go func() {
		for {
			select {
			case s := <-input1:
				c <- s
			case s := <-input2:
				c <- s
			}
		}
	}()
	return c
}

Wait Channels

存储顺序

go
type Message struct {
	str string
	wait chan bool
}

Daisy-chain

go
func f(left, right chan int) {
	left <- 1 + <-right
}

...

select

流程控制,类似 switch。switch 的 case 是表达式,select 的 case 是通信。

go
select {
case v1 := <-c1:
	fmt.Printf("received %v from c1\n", v1)
case v2 := <-c2:
	fmt.Printf("received %v from c2\n", v2)
case v3 <- 23:
	fmt.Printf("sent %v to c3\n", v3)
default:
	fmt.Printf("no one was ready to communicate\n")
}
  1. 如果 v1 和 v2 都有数据了,那么 select 会【随机】选择一个执行,因此你不能依赖 case 的顺序来编程。

  2. 没有 default,select 会阻塞直到存在成功通信的 case,否则 select 不会阻塞。

  3. timeout 特性:for select timeout

For-select loop

TODO

Quit channel

quit 管道:quit := make(chan bool)

接收消息的 quit 管道:quit := make(chan string)

Pipeline

go
func pipeline() {
	// input
	nums := []int{2, 3, 4, 6}
	// stage 1
	dataChan := sliceToChannel(nums)
	// stage 2
	finalChan := sq(dataChan)
	// stage 3
	for n := range finalChan {
		fmt.Println(n)
	}
}

func sliceToChannel(nums []int) <-chan int {
	out := make(chan int)
	go func() {
		for _, n := range nums {
			out <- n
		}
		close(out)
	}()
	return out
}

func sq(in <-chan int) <-chan int {
	out := make(chan int)
	go func() {
		for n := range in {
			out <- n * n
		}
		close(out)
	}()
	return out
}

其它

Advanced Go Concurrency Patterns 源代码

gobyexample