Go并发快速入门:Goroutine

Go并发:Goroutine

1.并发基础概念:进程、线程、协程

(1) 进程

可以比作食材加工的一系列动作

进程就是程序在操作系统中的一次执行过程,是由系统进行资源分配和调度的基本单位,进程是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进程都有一个自己的地址空间。一个进程至少有5种基本状态:初始态、执行态、等待状态、就绪状态、终止状态。

通俗讲: 进程就是一个正在执行的程序。

[一般情况] 一个程序一个进程

[多进程]] 一个程序多个进程

可以在终端输入以下内容,来列出所有的进程

ps -A

比如在Windows系统中,一个运行的xx.exe就是一个进程。

Go并发快速入门:Goroutine_第1张图片

(2) 线程

可以比作食材加工的某一个动作

线程是运算调度的最小单元,是进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。

进程与线程的区别如下

根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位

资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的

影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行

查看线程

  1. 进入 terminal
  2. 输入命令 ps-M[pid]
  3. 查看对应 pid 线程
(3) 协程

协程(goroutine) 是轻量级的执行线程。

Go并发快速入门:Goroutine_第2张图片
Go并发快速入门:Goroutine_第3张图片

实操

假设我们有一个函数叫做 action()。 我们一般会这样 同步地 调用它使用 go action() 在一个协程中调用这个函数。 这个新的 Go 协程将会 并发地 执行这个函数。

package main 

import (
	"fmt"
	// "time"
)

func action() {
	fmt.Println("Test Goroutine")
}

func main() {
	go action()

	// time.Sleep(2 * time.Second)
}

在这里插入图片描述

可见咩有任何输出,把注释内容取消注释再运行

Go并发快速入门:Goroutine_第4张图片

为什么要沉睡?

go 语言运行非常快,若没有沉睡,可能会导致

“协程还没有执行完, main 函数已经结束了”

最终导致协程结束前, main 函数已经被销毁

因此我们需要让主进程去等待一定时间的子协程,才能得到子协程的输出

2.多协程核心机理

Go并发快速入门:Goroutine_第5张图片

步骤

  • 任务切片/分配
  • 启动多个协程
  • 合并多个协程结果

Go并发快速入门:Goroutine_第6张图片

使用场景

  • 运算量比较多
  • 协程间依赖性比较弱

3.多协程等待实操

Go并发快速入门:Goroutine_第7张图片

我们可以使用通道来同步协程之间的执行状态。使用 wait group 等待多个协程完成

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup

	for i := 0; i < 2; i ++ {
		wg.Add(1)
		go func(num int) {
			fmt.Printf("Goroutine Test %d\n", num)
			wg.Done()
		}(i)
	}

	wg.Wait()
}

Go并发快速入门:Goroutine_第8张图片

更多细节清查阅 waitgroup

Go by Example 中文版: WaitGroup (gobyexample-cn.github.io)

你可能感兴趣的:(6.824,golang,开发语言,后端)