TAG
Golang
42 篇笔记
- 1.1 make vs newhistorical
1. 是什么 golang的内置函数 2. 为什么需要 分配内存空间 值类型的声明之后即可使用 引用类型的则需要分配空间 3. 使用 3.1. new 开辟一段内存,并置为零值,返回指向该类型内存地址的指针 3.1.1. 相当于&结构体{} 3.2. make 用于创建slice、map和chann
- 1.2 reflectionhistorical
1. 反射是什么 修改代码- 编译- 运行 正常来说我们要修改代码只能在编译前,反射能让我们在运行时修改代码 2. Golang如何实现反射 interface 当向interface变量赋予一个实体类型的时候,interface会存储实体的类型信息,反射就是通过interface的类型信息实现的
- 1.3 errorhistorical
1. exception和error Golang把错误分成exception和error - exception是严程序内部的BUG或者不可预料的情况 - error则是可以预期的,通过一个返回值来判断 2. 使用 2.1. exception - 内部BUG通过recovery捕获转换成erro
- 1.4 interfacehistorical
1. 有哪些 1.1. 空接口interface{} 可以接收任意类型的数据 它只要记录这个数据在哪儿,是什么类型的就足够了 1.1.1. 举例 底层结构如下 - 赋值 - 1.2. 非空接口 非空接口就是有方法列表的接口类型 一个变量要想赋值给一个非空接口类型,其类型必须要实现该接口要求的所有方法
- 1.5 functionhistorical
1. 是什么 - 函数是一等公民 - 有具名函数、匿名函数 - 把函数绑定在struct上就成了方法 2. 使用 2.1. 可变参数 2.2. 多返回值 go语言的函数可以返回多个值 2.2.1. 原理 - C语言的实现 在调用函数中分配返回值的空间,并将返回值的指针传给被调函数 - Go语言的实现
- 1.6 stringhistorical
1. 字符集 计算机只能存储字节(二进制),因此字符肯定也是用字节存储的 但是存储后怎么显示呢?需要建立字节和字符的映射,这就是字符集 比如 - 1.1. Unicode字符集 - 由来 最开始只有ASCII字符集,只支持英文; 为了支持中文简体,推出GB2312; 为了支持中文繁体,推出BIG5.
- 1.7 maphistorical
1. 什么是map O(1)效率存取k-v对 2. map如何实现 数组。数组中每个元素叫做桶 2.1. 写入 2.2. 读取 3. 如何找到key所属的桶 - 第一种:取模运算:hash%m - 第二种:按位与运算:hash&(m-1) - 这里m必须是2的幂次 4. 冲突了怎么办 - 开放寻址法
- 1.8 unsafehistorical
1. 指针类型 1.1. 是什么 变量的地址 1.2. 为什么需要指针类型 使用指针类型可以让callee修改caller传递的值 1.3. Golang的指针类型 Golang的指针类型是安全的 - 不能进行数学运算 - 不同类型的指针不能相互转换 - 不同类型的指针不能使用 == 或 != 比较
- 1.9 panic和recoverhistorical
1. 是什么 - panic是内置函数,可以停止正常的流程。 - recover是内置函数,可以捕获到panic,recover只在defer函数中有用。 2. 为什么需要 - panic一般用于不可恢复的错误,让程序不能继续进行 - recover为了防止panic之后整个进程都down掉,这个时
- 1.10 类型系统historical
1. 有哪些类型 1.1. 内置类型 1.2. 自定义类型 2. 类型元数据是什么 不管是内置类型哈还是自定义类型都有类型元数据,这些类型元数据共同构成了Go语言的类型系统 不管是内置类型还是自定义类型,都有一个对象头 2.1. 内置类型 内置类型除了对象头之外,还会有额外信息 2.1.1. 举例
- 1.11 arrayhistorical
1. 是什么 定长的数组 2. 使用 2.1. 数组的长度也是类型 2.2. 数组是值传递 赋值和函数传参时候是复制一份新的数组 2.3. 可以用range迭代 3. 原理 3.1. 数据结构 3.2. 创建 3.2.1. 初始化 - 第一种方式 会调用到cmd/compile/internal/t
- 1.12 slicehistorical
1. slice 是什么 支持动态扩容的数组 2. 为什么需要 slice array 元素长度固定,无法动态扩容 3. 如何使用 slice 3.1. 基本使用 3.2. 函数传参是引用 - 虽然传的是引用,但是为了避免扩容后 slice 改变,函数返回 slice 3.3. nil slice
- 1.13 deferhistorical
1. 什么是defer 让函数可以在当前函数执行完毕后执行的一种机制。 这里的函数执行完毕包括通过return正常结束或者panic导致的异常结束 2. 为什么需要defer 减少资源泄露的发生 3. 如何使用 在创建资源语句的附件,使用defer释放资源 3.1. 关闭资源 3.2. defer和
- 2.1 contexthistorical
1. context goroutine的上下文,在 goroutine 之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等。 控制并发的其中一种方式,另外一种是sync.WaitGroup.md 2. 使用 2.1. deadlines:超时取消 2.2. cancellation
- 2.2 sync.WaitGrouphistorical
1. 是什么 一种控制并发的方式 让一个goroutine等待其他goroutine完成 类似于9.CountDownLatch.md 2. 使用 3. 原理 - 里面维护了一个counter计数器 - Add 增加计数器 - Done 计数器-1 - Wait 等待计数器到达0时往下执行 4. 参
- 2.3 synchistorical
1. 是什么 提供了基本的 synchronization primitives 除了 Once 和 WaitGroup 外,大部分都是给 low-level 的库使用的 high-level 一般使用 channels 2. 有什么 2.1. Locker - 是个接口 - 有Lock和Unloc
- 2.4 sync.maphistorical
1. sync.map是什么 - 线程安全的Map - 底层使用乐观锁实现,所以适用竞争不大的场景 - 一次写多次读,如缓存的场景 - 多个goroutine读写的是没有交集的key 1.1. 并发安全的思路 - 加一把大锁 - 把map分成若干map,只操作小map 2. 使用 3. 源码分析 3
- 2.5 sync.poolhistorical
1. 是什么 保存temp object的pool。 temp表示这个对象可能会被回收,所以这个pool其实就是个cache 2. 为什么需要 将暂时不用的对象缓存起来,待下次需要的时候直接使用 这样就不用经过内存分配,减轻GC的压力 3. 怎么使用 3.1. fmt - Printf - Fpri
- 2.6 selecthistorical
1. 是什么 - 类似于IO多路复用 - 监听多个阻塞的事件,如果事件发生了,那么执行该事件逻辑 - 如果没有发生并有默认的事件,那么执行默认的事件逻辑 - 如果没有发生且没有默认的事件,那么一直阻塞 2. 使用 2.1. 基本使用 代码执行到 select 时,case 语句会按照源代码的顺序被评
- 2.7 sync.Oncehistorical
1. 是什么 Once 是一个对象,它提供了保证某个动作只被执行一次功能 说白了就是使方法只执行一次 2. 使用 2.1. 单例模式 单例模式.md 3. 原理 通过sync.atomic+sync.Mutex实现 - Do 方法为什么不直接 o.done == 0 而要使用 atomic.Load
- 2.8 sync.Mutexhistorical
1. Mutex是什么 - 互斥锁 - 实现了Locker接口,zero-value是没加锁的状态 - 加锁解锁可以在不同的goroutine中 2. 使用 2.1. 不使用Mutex的情况 2.2. 使用Mutex的情况
- 2.9 sync.RWMutexhistorical
1. 是什么 - 实现了Locker接口,是个读写锁 - Lock , RLock 分别用于加写锁和读锁 - Unlock , RUnlock 分别用于解写锁和读锁 2. 使用
- 2.10 sync.Condhistorical
1. 是什么 - 条件变量。Locker和Cond的关系类似于Java中Lock和Condition的关系。 - 所有方法必须持有Lock才能调用 - func NewCond(l Locker) Cond 使用Lock创建一个Cond - func (c Cond) Wait() 自动释放Lock
- 2.11 atomichistorical
1. atomic是什么 原子性 - 一个或多个操作要么全部执行,要么全部不执行。 - 最小的不可并行化的操作,就是同一时刻最多只有一个并发体对资源进行操作 - 一般情况下,原子操作都是通过“互斥”访问来保证的,通常由特殊的CPU指令提供保护 2. atomic value是什么 atomic包把底
- 2.12 channelhistorical
1. CSP并发模型 - 从内存的角度看,并行计算只有两种: 共享内存 、 消息通信 - 基于共享内存的并发模型通常提供互斥锁作为同步原语 - CSP 全称是 “Communicating Sequential Processes”,是一种基于消息通信的并发模型,由Tony Hoare于1977年提
- 2.13 concurrenthistorical
1. 有什么 1.1. goroutine+channel - goroutine.md - channel.md 1.2. sync包 sync.md 2. 同步 2.1. 顺序一致性模型 同一个Goroutine线程内部,顺序一致性内存模型是得到保证的 2.2. happens-before 不
- 2.14 goroutinehistorical
1. goroutine是什么 - 程序、进程、线程.md - Go语言实现的用户线程 - 相比较于线程,goroutine - 创建、销毁和切换:都在用户态完成无需进入内核 - 内存占用:默认栈大小为2K,并且可以动态扩缩容 2. goroutine使用 2.1. 创建协程 - go f(x, y
- 2.15 协程池historical
1. 协程池是什么 复用goroutine的池子 2. 为什么需要协程池 跟如何设计池化技术.md不同,由于 goroutine创建、销毁对象开销小:创建销毁是在用户态, goroutine数量理论上可以无限,一个goroutine占用内存仅仅不到2K 所以99%的情况下不需要协程池 但是在极限情况
- 3.1 GMPhistorical
1. goroutine调度器 - Golang中协程的调度模型,即有M个线程,N个协程,该怎么分配协程给线程执行 - 这个本质上和操作系统的调度器类似,即有M个处理器,N个线程,怎么分配处理器给线程执行 1.1. GM模型 - 最开始采用的是GM模型 - G:goroutine,M:内核线程 -
- 3.2 逃逸分析historical
1. 逃逸分析 如果是Java或C++创建出来的对象一般都是分配在堆上的,而Golang new出来的对象会根据逃逸分析决定是分配在堆还是栈上 2. 为什么需要逃逸分析 堆 栈 --- ----------- ------------- 回收 需要垃圾回收 退出函数即销毁 空间 大 小 3. 如何逃
- 3.3 Go构建过程historical
1. 文本文件 保存之后这个文件以二进制形式存储在磁盘中 使用vim打开,敲入 :%!xxd 最左边的地址列,中间是文本字符对应的十六进制ASCII编码,最右边是文本字符。 ASCII表可以通过 man ascii 查询 像这种把二进制通过字符表转换成人类可读的文件叫做文本文件,不可读的就是二进制文
- 3.4 内存管理historical
1. Golang内存分区 1.1. 栈 Golang栈管理.md 1.2. 堆 Golang堆管理.md 1.3. 全局区-静态全局变量区 - 全局变量+常量 - 分配:进程启动时 - 回收:进程退出时,由操作系统回收 1.4. 代码区 2. Golang runtime.MemStat Top
- 3.5 plan9汇编historical
1. Plan9汇编是什么 - 伪汇编 - 跟汇编一样需要通过汇编器转换成机器指令才能被CPU执行 - 伪的原因在于:对机器指令反汇编无法生成Go汇编,只能生成平台相关的汇编 2. 寄存器 - 通用寄存器 与AMD64机器的寄存器对应关系如下: 一般前六个用来传递参数,BP和SP用于管理栈顶和栈底
- 3.6 内存对齐historical
1. 机器字长 1.1. 地址总线和数据总线 - CPU通过地址总线到内存中寻址,而内存通过数据总线把数据传输给CPU - 地址总线的位数决定了内存大小:比如8bit地址总线,那么可以寻址[0, 255]总共256B的内存,内存超过256B也利用不了 - 数据总线则决定了一次性能传输多少数据:比如要
- 3.7 GChistorical
1. 什么是GC GC.md 2. 为什么需要GC GC.md 2.1. GC的问题 2.1.1. 内存泄露 Golang内存泄露.md 2.1.2. STW 通过三色标记法减少GC STW的时间 3. 如何进行垃圾回收 3.1. GC触发 - 主动触发 - 通过调用 runtime.GC 来触发
- 3.8 Golang栈管理historical
1. 栈是什么 - 空间小,数据存放时间较短暂。栈在高地址,从高地址向低地址增长 - 分配:函数调用自动分配 - 回收:函数返回自动回收 2. Golang栈的特点 2.1. 动态扩容 - go runtime不是给每个goroutine分配固定的空间,而是需要的动态分配栈空间 - 创建gorout
- 3.9 Golang堆管理historical
1. 堆是什么 - 空间大,数据存放时间较长。堆在低地址,从低地址向高地址增长 - 分配:程序员手动分配 - 回收:GC Go的内存管理是runtime,也就是说并不是每次内存分配都需要进行系统调用。 采用的算法是 TCMalloc 算法,即 Thread-Caching Malloc 。 他把可用
- 4.1 unittesthistorical
1. 是什么 单元测试 2. 使用 - 文件名 xxx test.go - 导入 testing - 函数名必须 TestXXX - 运行 - go test . 3. 参考 - Go语言基础之单元测试 \ 李文周的博客 - testing \- The Go Programming Languag
- 4.2 pprofhistorical
1. pprof是什么 Golang的性能分析工具。 2. 如何使用pprof 有两个库: runtime/pprof :采集工具型应用运行数据进行分析 net/http/pprof :采集web应用运行时数据进行分析 benchmark :压测 2.1. runtime/pprof 2.1.1.
- 4.3 benchmarkhistorical
1. 使用 - bench.go - bench test.go - 测试: - go test -bench=. - 查看内存分配信息: go test -bench=. -benchmem - 生成CPU信息: go test -bench=. -benchmem -cpuprofile pro
- 4.4 Golang内存泄露historical
1. 内存泄露 内存泄露.md 2. Golang内存泄露 2.1. root对象引用 2.2. goroutine 泄漏 goroutine泄露:原理、场景、检测和防范 \- SegmentFault 思否 - 如果你启动了一个 goroutine,但并没有符合预期的退出,那么直到程序结束这个go
- 4.5 tracehistorical
1. 使用 步骤如下: 1. 导入包: import runtime/trace 2. 开启分析: trace.Start(file) 停止分析: trace.Stop() 3. 命令行分析 - go tool trace trace.out - 2. 参考 Go execution tracer