小试牛刀
程序员文章站
2024-02-23 08:05:22
...
go 使并发编程变得简单
func square() {
naturals := make(chan int)
squares := make(chan int)
// Counter
go func() {
for x := 0; x < 10; x++ {
naturals <- x
}
close(naturals)
}()
// Squarer
go func() {
for {
x, ok := <-naturals
if !ok {
break // channel was closed and drained
}
squares <- x * x
}
close(squares)
}()
// Printer
for {
x, ok := <-squares
if !ok {
break
}
fmt.Println(x)
}
}
当一个 channel 被 close 后再 send 会 panic, 再取值不会阻塞了而是直接返回 zero value (零值,这里 int 会返回 0)。可通过第二个参数 ok 判断 channel 是否关闭且里面的值已经取净(drained)。
range 可遍历 channel 并在 channel close 且 drained 后结束遍历,所以上面的例子可用 range 简化
func square() {
naturals := make(chan int)
squares := make(chan int)
// Counter
go func() {
for x := 0; x < 10; x++ {
naturals <- x
}
close(naturals)
}()
// Squarer
go func() {
for x := range naturals {
squares <- x * x
}
close(squares)
}()
// Printer
for x := range squares {
fmt.Println(x)
}
}
看看 select 用法
package main
import (
"fmt"
"os"
"time"
)
func couter() {
tick := time.Tick(1 * time.Second)
abort := make(chan struct{})
go func() {
os.Stdin.Read(make([]byte, 1)) // 按enter 键 abort
abort <- struct{}{}
}()
for countdown := 10; countdown > 0; countdown-- {
select {
case <-abort:
fmt.Println("launch aborted")
return
case <-tick:
fmt.Println(countdown)
}
}
fmt.Println("launched")
}