【Go并发】— 轻量级线程选手goroutine

215 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

🎐 放在前面说的话

大家好,我是北 👧🏻

本科在读,此为日常捣鼓.

如有不对,请多指教,也欢迎大家来跟我讨论鸭 👏👏👏

今天是我们「Go并发」系列的第一篇:「轻量级线程选手goroutine」; image.png Let’s get it

一、goroutine

1. goroutine概念

  • Go通过关键词go来创建goroutine实现并发。
  • goroutine类似线程,属于用户态的轻量级线程,可以创建成千上万个goroutine进行并发工作,故先后执行顺序不确定(goroutine是由Go语言的运行时调度完成,线程时由操作系统调度完成)

2. goroutine优势

  • 可增长的分段线堆,即它们在调用时,才会占用更多的内存
  • 启动时间比线程快
  • 原生支持channel安全进行通信

二.goroutine的使用

在调用函数时,在函数前加上go关键词即可.一个函数可以被创建多个 goroutine,一个 goroutine 必定对应一个函数。

1)格式

普通创建:

go 函数名(参数)

或者用匿名函数创建:

go func(形参){ 函数体 }(实参)

go创建goroutine时,会忽略被调用函数的返回值.若需要在goroutine中返回数据,可用channel实现,下一篇会说明.

2)启动单个goroutine试试鲜

func hello(){

	fmt.Println("Hello goroutine!")
	
}

func main(){

	hello()
	
	fmt.Println("main goroutine done!")
	
}

执行打印:

image.png

现在,我们在原基础上尝试一下,在main主函数里再起一个goroutine

func test() {

    fmt.Println("Hello goroutine!")

}

func main() {

    go hello()

    fmt.Println("main goroutine done!")

}

这次只打印了:

image.png

为什么?

因为在程序启动时,Go程序会为main()函数创建一个默认的goroutine。当main()函数返回的时候,默认的goroutine就结束了,在main函数中启动的goroutine也一并结束。它如同一个主宰,它亡,子民也要跟随它而去。

怎么解决?

让main()函数里的goroutine等一等,可用time.sleepWaitGroup

var wg sync.WaitGroup

  

func hello() {

    fmt.Println("Hello goroutine!")

    wg.Done() // 通知wg把计数器-1

}

func main() {

    wg.Add(1) // 计数器+1

    go hello()

    fmt.Println("main goroutine done!")

    //time.Sleep(time.Second * 1)

    wg.Wait() // 等待所有goroutine结束,main()函数主线程再结束

}

3)启动多个goroutine试试鲜

//创建等待组

var wg sync.WaitGroup

  

func hello(i int) {

    fmt.Printf("hello goroutine %d\n", i)

    wg.Done() // 通知wg把计数器-1

  

}

  

//程序启动时会创建一个名为main的goroutine去执行

func main() {

    // for循环,创建3个goroutine

    for i := 0; i < 3; i++ {

        wg.Add(1)   // 计数器+1

        go hello(i) // 开启一个单独的Goroutine去执行当前函数

    }

    fmt.Println("main goroutine")

    wg.Wait() // 等待所有goroutine结束,main()函数主线程再结束

}

执行打印:

image.png

以上用到的WaitGroup,我们会再出一篇关于并发编程中sync包的使用

📖一些概念科普

并发&并行

  • 并发:同一时间内执行多个任务(我在vx上和两个朋友聊天)

  • 并行:同一时刻执行多个任务 (我和我朋友都在vx上和朋友聊天)

进程&线程&协程

  • 进程:程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位 (进程是车间,车间里必须有一个或以上的工人)

  • 线程:线程是进程的一个执行实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个线程上可以跑多个协程,协程是轻量级的线程。 (线程是车间里自由行动的工人)

  • 协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的。 (工人手上的工具)

  • CPU:中央处理器,计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。 (CPU是一个含有很多很多的车间大工厂)

🎉 放在后面的话

Go语言作为新兴的语言,最近发展势头也很是迅猛,其最大的特点就是原生支持并发。它使用的是goroutine模型.goroutine 是 Go 语言内建的语言特性,它使用了一个称为协程的概念、易于使用,并且性能较高.Go 运行时调度器可将goroutine复用到其他线程上,当下线程阻塞时,Go 运行时将阻塞的 goroutine移动到另一个可运行的内核线程,提高工作效率。goroutine还原生支持很多工具,例如goroutines之间安全通信的 channel。如果大家需要开发高并发的应用程序或者服务等,Go是一个很不错的选择.