Go 并发(Goroutines)
Go语言提供了称为Goroutines的特殊功能。Goroutine是一种函数或方法,可与程序中存在的任何其他Goroutine一起独立且同时执行。换句话说,每个Go语言中同时执行的活动称为Goroutines,您可以将Goroutine视为轻量级线程。与线程相比,创建Goroutines的成本非常小。每个程序至少包含一个Goroutine,并且该Goroutine被称为主Goroutine。如果主Goroutine终止,则所有Goroutine在主Goroutine之下运行,那么程序中存在的所有goroutine也将终止;Goroutine始终在后台运行。
如何创建Goroutine?
您只需使用go关键字作为函数或方法调用的前缀,即可创建自己的Goroutine,如以下语法所示:
语法:
func name(){ // 语句 } // 在函数名前面,使用go关键字 go name()
package main import "fmt" func display(str string) { for w := 0; w < 6; w++ { fmt.Println(str) } } func main() { // 调用Goroutine go display("Welcome") //正常调用函数 display("(cainiaoplus.com)") }
输出:
(cainiaoplus.com) (cainiaoplus.com) (cainiaoplus.com) (cainiaoplus.com) (cainiaoplus.com) (cainiaoplus.com)
在上面的示例中,我们仅创建了display()函数,然后以两种不同的方式调用此函数,第一种是Goroutine,即go display("Welcome"),另一种是常规调用函数,即display("nhooo")
但是您可能发现问题了,它只显示调用普通函数的结果,而不显示Goroutine的结果,因为执行新的Goroutine时,Goroutine调用会立即返回。它不像普通函数那样等待Goroutine完成执行,它们总是在Goroutine调用后一直前进到下一行,并忽略Goroutine返回的值。因此,为了正确执行Goroutine,我们对程序进行了一些更改,如以下代码所示:
修改后的Goroutine示例:
package main import ( "fmt" "time" ) func display(str string) { for w := 0; w < 6; w++ { time.Sleep(1 * time.Second) fmt.Println(str) } } func main() { // 调用Goroutine go display("Welcome") //调用普通函数 display("nhooo") }
输出:
Welcome nhooo nhooo Welcome Welcome nhooo nhooo Welcome Welcome nhooo nhooo
我们在程序中添加了Sleep()方法,它使主Goroutine在新Goroutine执行的1秒之间睡眠1秒,在屏幕上显示欢迎,然后在1秒的主Goroutine重新调度并执行其操作后终止。这个过程一直持续到z的值<6,之后主Goroutine终止。在这里,Goroutine和普通函数同时工作。
Goroutines的优点
Goroutine比线程开销小。
Goroutine存储在堆栈中,并且堆栈的大小可以根据程序的要求而增大和缩小。但是在线程中,堆栈的大小是固定的。
Goroutine可以使用通道进行通信,并且这些通道经过特殊设计,可以防止在使用Goroutines访问共享内存时出现争用情况。
假设一个程序有一个线程,并且该线程有许多与之关联的Goroutine。如果由于资源需求,任何Goroutine阻塞了线程,则所有其余Goroutine将分配给新创建的OS线程。所有这些细节对程序员都是隐藏的。
匿名Goroutine
在Go语言中,您还可以为匿名函数启动Goroutine,换句话说,您可以简单地通过使用go关键字作为该函数的前缀来创建匿名Goroutine,如以下语法所示:
语法:
//匿名函数调用 go func (parameter_list){ // 语句 }(arguments)
package main import ( "fmt" "time" ) func main() { fmt.Println("Welcome!! to Main function") //创建匿名Goroutine go func() { fmt.Println("Welcome!! to (cainiaoplus.com)") }() time.Sleep(1 * time.Second) fmt.Println("GoodBye!! to Main function") }
输出:
Welcome!! to Main function Welcome!! to (cainiaoplus.com) GoodBye!! to Main function