前言
再写go的时候学到的一些特性和使用方法,在这记录一下,感觉面试什么的会遇到。
go工作池
worker pool,也就是线程池thread pool,不过在go里使用的goroutine而非线程。
goroutine
先理解一下goroutine,我个人并没有仔细研究过go的原理,之前一直写java和python,所以goroutine对我来说是个很新奇的东西。
线程、协程和goroutine
我么都知道go是从语言层面就支持并发。为了更好的理解goroutine,先复习一下线程和协程:
- 线程
有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程的切换一般也由操作系统调度。 - 协程
又称微线程与子例程(或者称为函数)一样,协程(coroutine)也是一种程序组件。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。
和线程类似,共享堆,不共享栈,协程的切换一般由程序员在代码中显式控制。它避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂。
线程和协程的区别:
- 进程是cpu分配的基本单位,线程是独立运行和独立调度的基本单位,协程是基于线程上更轻量化的存在
- 一个进程可以拥有多个协程
- 进程是同步机制,协程是异步机制
goroutine本质上是一个协程,不同于协程的是,golang在 runtime、系统调用等多方面对 goroutine 调度进行了封装和处理。Go程序会智能地将 goroutine 中的任务合理地分配给每个CPU。
但盲目使用goroutine会使得cpu的负荷过高。
context机制
go的上下文是专指goroutine的上下文,包含goroutine的运行状态、环境、现场等信息
当我们在处理一个比较复杂的协程环境,如一个请求衍生出多个协程,这些协程共用一些变量,或完成相同的工作,那这是想用cl关闭这些协程
go异步
释义
先抄一段同步与异步的解释:
同步异步 , 举个例子来说,一家餐厅吧来了5个客人,同步的意思就是说,来第一个点菜,点了个鱼,好, 厨师去捉鱼杀鱼,过了半小时鱼好了给第一位客人,开始下位一位客人,就这样一个一个来,按顺序来。
相同, 异步呢,异步的意思就是来第一位客人,点什么,点鱼,给它一个牌子,让他去一边等吧,下一位客人接着点菜,点完接着点让厨师做去吧,哪个的菜先好就先端出来。
同步的优点是:同步是按照顺序一个一个来,不会乱掉,更不会出现上面代码没有执行完就执行下面的代码, 缺点:是解析的速度没有异步的快。
异步的优点是:异步是接取一个任务,直接给后台,在接下一个任务,一直一直这样,谁的先读取完先执行谁的, 缺点:没有顺序 ,谁先读取完先执行谁的 ,会出现上面的代码还没出来下面的就已经出来了,会报错。
在go中,异步表现为不同的goroutine开启任务。
阻塞与非阻塞
简单来说,就是是否等待结果。等待结果就是阻塞,不等待结果就是非阻塞。
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
正常来说,阻塞更符合我们的编程思维,也就是结果重要。
简单贴一个代码:
package main
import "fmt"
func main() {
// 方法的两个参数
a := 1
b := 2
// 从管道中接收结果,这一步是阻塞的,因为在等待结果的产出
sum := <-addAsync(a, b)
fmt.Println(sum)
}
func addAsync(a int, b int) chan int {
// 使用管道接收结果,注意需要设置一个缓冲位,否则没有取结果的话这个 goroutine 会被阻塞
resultChan := make(chan int, 1)
go func() {
// 在新的 goroutine 中计算结果,并将结果发送到管道
resultChan <- a + b
}()
return resultChan
}
非阻塞代码:
package main
import (
"fmt"
"time"
)
func main() {
// 方法的两个参数
a := 1
b := 2
// 调用方法的时候加上回调函数
// 这个回调函数会在得到结果之后执行
addWithCallback(a, b, func(sum int) {
fmt.Println(sum)
})
// 防止 main goroutine 比异步任务的 goroutine 先退出
time.Sleep(time.Second)
}
func addWithCallback(a int, b int, callback func(sum int)) {
go func() {
// 在新的 goroutine 中计算结果,并将结果传递给回调函数
sum := a + b
callback(sum)
}()
}
Comments | NOTHING