哲学理解: go 语言是个效率机器,对于 goroutine 的执行,是个墙头草的执行方式,遇到 channel 读写阻塞,sleep,等,逻辑处理器都会去执行队列中的其它 goroutine。永远在干活,绝不空转!
GO 版本管理
使用 g(Go 版本管理器)
g 是一个专门用于管理 Go 版本的工具:
shellscript
# 安装 g
curl -sSL https://git.io/g-install | sh -s
# 安装最新版本的 Go
g install latest
# 升级到最新版本
g install latest
- 语言入门 重点:需要 package main,需要 main 函数 但是如果你想要编译成可执行文件(使用 go build 或 go run),就必须有 main package 和 main 函数。没有 main package 的代码只能作为库被其他程序导入使用。
package main
import "fmt"
func main() {
fmt.Printf("hello, world!")
}
- 语法
- 数组
var a [3]string = [3]string{1,3,4}
- 动态数组
var a = make([]int, 0, 5);
append(a, 1,2,3,4,5);
append(a, 6);
// 上述 make 创造了一个 起始长度为 0,最大容量为 5的整数数组,当容量超出 5 个,数组自动扩容
- 当切片容量不足时,Go会分配一个更大的底层数组
- 需要将原数组的所有元素复制到新数组中
- 原数组被垃圾回收器回收
- map
var a [string]string = [string]string{"hello": "111"}
- make 函数,申请容量
make([string]string, 3) //3 是一个预期,实际可以放超过 3 个的成员,只不过超过 3 个会动态扩容。3 以内的成员追加性能好于 3 以外的成员追加
没有容量提示 = 用小箱子装东西 - 装满了要换大箱子 - 把旧箱子的东西倒到新箱子里 - 重复多次,很麻烦
有容量提示 = 一开始就用大箱子 - 一次性装完,不用换箱子 - 省时省力
- 函数
func c(a, b int) (int, error) {
}
- 包含函数名,参数,和返回值(可以是多个返回值,逗号隔开)
- 如果参数和返回值的类型各自都是一样,那么可以只为最后一个参数设置类型
问题
- goroutine 弥补了传统的系统线程的哪些不足
- 2kb->2M 让百万并发成为可能,并且相比系统线程,开 1000 个线程,go并没有真开启 1000 个系统线程,还是 8 个(对于 8CPU 来说)线程,来处理 1000 个任务
- 阻塞,系统线程阻塞是依旧是占用的,goroutine 的机制可以利用阻塞的线程切换到其它 goroutine
- 线程的中断,保存,恢复——开销:几微秒,goroutine 切换:几十纳秒
总结:也就是 goroutine 通过编译,接管了 任务切换时的内核态内存占用问题?通过用户态内存处理了所有的状态数据,没有把任务直接交给操作系统