2.25 Go之Goroutine(轻量级线程)
网络编程
编写Socket网络程序需要提前准备一个线程池,为每个Socket的收发包分配一个线程。
线程池与CPU数量的对应关系:
开发人员需要在线程数量和CPU数量间建立一个对应关系,以保证每个任务能及时地被分配到CPU上进行处理,同时避免多个任务频繁地在线程间切换执行而损失效率。
goroutine机制:
使用者分配足够多的任务,系统能自动帮助使用者把任务分配到CPU上,让这些任务尽量并发运作。
使用普通函数创建goroutine
goroutine特点:
-
go关键字为一个函数创建一个goroutine -
一个函数可以被创建多个
goroutine -
一个
goroutine必定对应一个函数
一个普通的goroutine
格式:
普通的goroutine写法:
go 函数名(参数列表)
/*
函数名:要调用的函数名。
参数列表:调用函数需要传入的参数。
*/
注意:
使用go关键字创建goroutine时,被调用的函数返回值会被忽略
需要在goroutine中返回数据,使用后面介绍的通道(channel)特性,通过通道把数据从goroutine中作为返回值传出。
示例代码:
使用go关键字,将running()函数并发执行,每隔一秒打印一次计数器,main的goroutine则等待用户输入,两个行为可以同时进行
package main
import (
"fmt"
"time"
)
/*
定义runnning函数,同时定义接收命令行输入函数
并发执行
*/
func runnnig() {
var times int
// 无限循环添加
for {
times++
// 打印结果
fmt.Println("answer:", times)
// 延时一秒
time.Sleep(time.Second)
}
}
// 并发执行
func main() {
// 定义并发执行程序
go runnnig()
// 命令行接收输入
var input string
fmt.Scanln(&input)
}
代码执行顺序:

分析:
Go程序在启动时,运行时(runtime)会默认为main()函数创建一个goroutine。在main()函数的goroutine中执行到go running 语句时,归属于running()函数的goroutine被创建,running()函数开始在自己的goroutine中执行。此时,main()继续执行,两个goroutine通过Go程序的调度机制同时运作。
使用匿名函数创建goroutine
go关键字可以为匿名函数或者闭包启动goroutine
-
使用你们函数创建
goroutine的格式
匿名函数或闭包创建goroutine时,除了将函数定义部分写在go的后面之外,还需要加上匿名函数的调用参数:
go func(参数列表) {
函数体
}(调用参数列表)
/*
参数列表:函数体内的参数变量列表。
函数体:匿名函数的代码。
调用参数列表:启动 goroutine 时,需要向匿名函数传递的调用参数。--->写在调用参数列表中的才是真实的入参
*/
匿名函数创建goroutine示例:
在main()函数中创建一个匿名函数并为匿名函数启动goroutine。匿名函数没有参数。代码将并行执行定时打印计数的效果
package main
import (
"fmt"
"time"
)
/*
使用匿名参数的方法创建一个goroutine
*/
func main() {
// 声明一个匿名goroutine
/*
没有调用参数,所以再启动main的时候会直接被执行
*/
go func() {
var times int
// 无线添加
for {
times++
fmt.Println("tick", times)
// 等待
time.Sleep(time.Second)
}
}()
// 接收命令行参数
var input string
fmt.Scanln(&input)
}
goroutine特点:
所有goroutine在main()函数结束时会一同结束
终止goroutine的最好方法就是自然返回goroutine对应的函数。
截止Go 1.9版本,暂时没有标准接口获取goroutine的

浙公网安备 33010602011771号