go 语言并发基础知识

Go 语言的并发机制运用起来是非常简单的,在启动并发的基础上直接添加了语言级的关键字 go 就可以实现。

进程/线程

进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。

线程是进程的一个执行实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

一个进程可以创建和撤销多个线程,同一个进程中的多个线程之间可以并发执行。

并发/并行

多线程程序在单核心的 cpu 上运行,称为并发;多线程程序在多核心的 cpu 上运行,称为并行。

并发与并行并不相同,并发主要由切换时间片来实现“同时”运行,并行则是直接利用多核实现多线程的运行,Go程序可以设置使用核心数,以发挥多核计算机的能力。

协程/线程

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

线程:一个线程上可以跑多个协程,协程是轻量级的线程。

优雅的并发编程范式,完善的并发支持,出色的并发性能是Go语言区别于其他语言的一大特色。使用Go语言开发服务器程序时,就需要对它的并发机制有深入的了解。

Goroutine 介绍

goroutine 是一种非常轻量级的实现,可在单个进程里执行成千上万的并发任务,它是Go语言并发设计的核心。

说到底 goroutine 其实就是线程,但是它比线程更小,十几个 goroutine 可能体现在底层就是五六个线程,而且Go语言内部也实现了 goroutine 之间的内存共享。

使用 go 关键字就可以创建 goroutine,将 go 声明放到一个需调用的函数之前,在相同地址空间调用运行这个函数,这样该函数执行时便会作为一个独立的并发线程,这种线程在Go语言中则被称为 goroutine。

演示代码

package main

import "time"

func say() {
	for i := 1; i <= 10; i++ {
		println("say ... ", i)
		time.Sleep(time.Millisecond * 100)
	}
}

func sayHi() {
	for i := 1; i <= 10; i++ {
		println("say hi ... ", i)
		time.Sleep(time.Millisecond * 100)
	}
}

func main() {
	// 开启协程
	go say()
	go sayHi()
	// 主线程与协程同时运行,当主进程运行完毕后协程也会被关闭
	// 所以主线程应该等待协程运行完成后再退出
	time.Sleep(time.Second * 10)
	println("main end")
}