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