, 0, 200, 200)
}
func (i Image) At(x, y int) color.Color {
return color.RGBA{uint8(x), uint8(y), uint8(255), uint8(255)}
}
func main() {
m := Image{}
pic.ShowImage(m)
}
五、并发
1.Go程
Go程(goroutine)是由Go运行时管理的轻量级线程。
go f()
2.信道
信道是带有类型的管道,你可以通过它用信道操作符<-
来发送或者接收值。
ch <- v // 将v发送至信道ch
v := <-ch // 从ch接收值并赋予v
和映射与切片一样,信道在使用前必须创建:
ch := make(chan int)
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 将和送入c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s) / 2], c)
go sum(s[len(s) / 2:], c)
x, y := <-c , <-c // 从c中接收
fmt.Println(x, y)
// -5
// 17
}
信道可以是带缓冲的。将缓冲长度作为第二个参数提供给make
来初始化一个带缓冲的信道。
ch := make(chan int, 100)
3.range和close
发送者可通过close
关闭一个信道来表示没有需要发送的值了。
接收者可以通过为接收表达式分配第二个参数来测试信道是否被关闭;若没有值可以接收且信道已被关闭,那么在执行完
v, ok := <-ch
之后ok
会被设置为false
。
循环for i := range c
会不断从信道接收值,直到它被关闭。
只有发送者才能关闭信道。向一个已经关闭的信道发送数据会引发程序恐慌(panic)。
信道与文件不同,通常情况下无需关闭它们。只有在必须告诉接收者不再有需要发送的值时才有必要关闭,例如终止一个range
循环。
通过信道实现斐波那契数列:
package main
import "fmt"
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x + y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}
4.select语句
select
语句使一个Go程可以等待多个通信操作。
select
会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x + y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
// 0 1 1 2 3 5 8 13 21 34 quit
}
当select
中的其它分支都没有准备好时,default
分支就会执行。
为了在尝试发送或者接收时不发生阻塞,可以使用default
分支:
select {
case i := <-c:
// 使用i
default:
// 从c中接收会阻塞时执行
}
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(1000 * time.Millisecond)
boom := time.After(5000 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(500 * time.Millisecond)
}
}
}
The end. Last updated by Jehorn, 3:30 PM, Tuesday, March 26, 2019 (GMT+8)