5.1.2 goroutine的基本使用
goroutine的使用比较简单。下面先通过一个例子来看一下如何创建一个单个的goroutine。
book/ch05/5.1/base/main.go
1. package main
2.
3. import (
4. "fmt"
5. "time"
6. )
7.
8. func HelloWorld() {
9. fmt.Println("Hello,World!")
10. }
11.
12. func main() {
13. go HelloWorld()
14. time.Sleep(1*time.Second)
15. fmt.Println("The End!")
16. }
17. //以下为程序执行结果
18. Hello,World!
19. The End!
第8行至第10行,定义一个函数,函数里面仅仅是打印“Hello,World!”。
第12行至第16行,使用go关键字启动goroutine,注意第13行,这里启动了一个goroutine来运行HelloWorld函数。程序执行完成后可以看到第18行和第19行的输出。不过为什么要在第14行加上一个程序的休眠呢?因为如果不加程序休眠,很可能最终只打印“The End!”,这是缘于main函数在HelloWorld函数的goroutine执行完之前已经完成,只要main函数结束就会结束程序中所有的goroutine,故而为了安全加上了休眠。
这个例子非常简单,goroutine里面仅仅打印了一个字符串。如果goroutine里面的代码比较复杂,goroutine和main函数的goroutine之间的顺序能否有保证?再来看一个示例:
book/ch05/5.1/adv1/main.go
1. package main
2.
3. import (
4. "fmt"
5. "time"
6. )
7.
8. func main() {
9. go func() {
10. for i:=10;i<20;i++{
11. fmt.Print(" ",i)
12. }
13. }()
14. fmt.Println()
15. for i:=0;i<10;i++{
16. fmt.Print(" ",i)
17. }
18. time.Sleep(2*time.Second)
19. }
20.
21. //以下为程序执行结果
22. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
23. 0 10 11 1 2 3 4 5 6 7 8 9 12 13 14 15 16 17 18 19
第9行至第13行,定义了一个匿名函数,并且直接使用go关键字运行,函数的主体部分是打印从10到19的数字。
第14行,输出一个换行。
第15行至第17行,通过main函数打印0到9。
重点来看第22行和第23行的运行结果,这两次运行结果不同,就是因为main函数的goroutine(可以叫作主goroutine)和自启动goroutine之间是并发执行的,彼此没有关系,所以0到9是从小到大的顺序,10到19也保持着这个顺序,可是两个线程之间混在一起,没有同步关系,如果要实现同步关系需要进行额外的编程。
第14行的换行之所以在打印结果上没有体现出来,是因为这两次都是先执行了换行,所以从结果中看不出来。
上面的例子仅启动了一个goroutine,接下来启动多个goroutine,更直观地感受一下并发执行的效果,示例代码如下:
book/ch05/5.1/adv2/main.go
1. package main
2.
3. import (
4. "fmt"
5. "time"
6. )
7.
8. func main() {
9. for i:=0;i<20;i++{
10. go func(i int) {
11. fmt.Print(" ",i)
12. }(i)
13. }
14. time.Sleep(2*time.Second)
15. fmt.Println("The End!")
16. }
17. //以下为程序两次执行结果
18. 3 1 11 5 12 13 14 0 2 7 4 17 16 18 9 8 6 10 19 15The End!
19. 1 10 0 15 11 12 13 14 5 2 3 4 17 16 7 6 18 8 9 19The End!
第9行至第13行,在循环语句中通过匿名函数启动了20个goroutine,每个goroutine打印0~19中的一个数字。结合第18行和第19行两次执行的结果来看,每次执行的打印顺序是不一样的,因为每次都是并发执行,不额外控制的话顺序就有随机性。
第14行的休眠是为了保证所有的goroutine都执行完成。有了第14行的休眠可以看到每次第15行的打印都会在最后。