package main
import(
"fmt"
"time"
)
func main(){
go spinner(100 * time.Millisecond)
const n = 45
fibN := fib(n)
fmt.Printf("\rFibonacci(%d) = %d\n",n,fibN)
}
func spinner(delay time.Duration){
for{
for _, r := range `-\|/`{
fmt.Printf("\r%c", r)
time.Sleep(delay)
}
}
}
func fib(x int)int{
if x < 2{
return x
}
return fib(x-2) + fib(x - 1)
}
spinner为死循环程序,循环打印-\|/,模拟程序运行
通过go 启动一个线程调用spinner函数
然后计算fib,输出结果,main函数结束,强制终止所有线程。
二.通道
package main
import(
"fmt"
)
func counter(out chan<- int){
for x := 0; x < 100; x++{
out <- x
}
close(out)
}
func squarer(out chan<- int, in <-chan int){
for v := range in{
out <- v * v
}
close(out)
}
func printer(in <-chan int){
for v := range in{
fmt.Println(v)
}
}
func main(){
naturals := make(chan int)
squares := make(chan int)
go counter(naturals)
go squarer(squares, naturals)
printer(squares)
}
定义naturals,squares为传输int的管道,counter为不断传输自然数的通道,squarer不断接收naturals通道的输入,再将平方输出到squares通道,printer则打印squares通道中的数。counter,squarer通过gorountine线程调用,printer在主线程中调用,直到printer结束。
在 Go 语言中,从一个无缓冲通道中读取数据时,如果没有数据可用,读取操作会被阻塞,直到有数据可用为止。同样地,向一个无缓冲通道中写入数据时,如果通道已满,写入操作也会被阻塞,直到有空间可用为止。
所以squarer会阻塞等待counter输入,printer会阻塞等待squarer输入。
三、使用select多路复用
package main
import(
"fmt"
"os"
"time"
)
func main(){
abort := make(chan struct{})
go func(){
os.Stdin.Read(make([]byte, 1))
abort <- struct{}{}
}()
fmt.Println("commencing countdown. Press return to abort")
tick := time.Tick(1*time.Second)
for countdown := 10; countdown > 0; countdown--{
fmt.Println(countdown)
select{
case <- tick:
case <- abort:
fmt.Println("launch aborted")
return
}
}
launch()
}
func launch(){
fmt.Println("lift off")
}
- time.Tick函数返回一个通道,定期发送一个事件
- 定义abort通道,标记其它线程触发事件,通过abort中断函数
- go func()调用线程获取命令行输入,若有输入,则触发abort通道
- 使用select进行多路复用,因为通道在操作完成前都会被阻塞,所以需要使用select