Go语言学习之 Goroutine(协程)

306 阅读3分钟

前端尝试转GO学习(第五天)

goroutineGo 的并发机制中的主角。代表指令流及其执行环境,是被调度的基本单位。

Go 语言支持并发,只需要通过 go 关键字来开启 goroutine 即可。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。

go 函数名( 参数列表 )

例如:

go f(x, y, z)

Go 允许使用 go 语句开启一个新的线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。(不同线程间共享同一个内存空间,但不共享栈且各自并发执行)

groutine 是与其他函数或方法一起并发运行的工作方式。协程可以看作是轻量级线程。与线程相比,创建一个协程的成本很小。因此在 Go 应用中,常常会看到会有很多协程并发地运行。

进程:进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。

线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。

协程,是一种基于线程之上,但又比线程更加轻量级的存在,正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。

无标题-2022-07-21-1034.excalidraw.png

goroutine 和新创建的 goroutine 拥有并发性,且主 goroutine 在执行时并不会等待被调用函数执行结束,故主 goroutine 输出和新 goroutine 输出可能以任何顺序交错展现。

无标题-2022-07-21-1112.excalidraw.png

启动一个 Go 协程

调用函数或者方法时,如果在前面加上关键字 go ,就可以让一个新的 go 协程并发地运行。

// 定义一个函数
func functionName() {
    // code
}
// 执行一个函数
functionName()

// 开启一个协程执行这个函数 
go functionName() 

输出的 hello 和 world 是没有固定先后顺序。因为它们是两个 goroutine 在执行

func say(s string) {
   for i := 0; i < 5; i++ {
      // 避免观察不到并发效果 加个休眠
      time.Sleep(100 * time.Millisecond)
      fmt.Println(s)
   }
}

func main() {
   go say("world")
   say("hello")
}
world
hello
hello
world
world
hello
hello
world
world
hello

启动多个 Go 协程

两个协程就如两个线程一样,并发执行:

func say(s string) {
   for i := 0; i < 5; i++ {
      time.Sleep(100 * time.Millisecond)
      fmt.Println(s)
   }
}

func main() {
   go say("world")
   go say("hello")
   time.Sleep(time.Second)
}

Golang 的并发机制是 NodeJS 的普适版,拥有能够更好利用多核计算力的优势;和 采用 OS 线程、阻塞 I/O、GIL 的 Python 并发模式 相比则更是云泥之别。正是更为精巧的并发机制和简单的并发原语,使得 Concurrency 成为 Go 语言最大的卖点。

参考文章:

本文正在参加技术专题18期-聊聊Go语言框架