golang知识点整理(持续更新)

  • 对golang的概括理解
Go是一种编译型语言,结合了解释型语言的优点(如调试效率,跨平台),动态类型语言的优点(如开发效率),以及静态类型的优点(如安全性);
Go是静态类型语言,类型系统没有层级,因此无需在类型关系定义上耗费过多时间;
Go是垃圾回收型的语言,并为并发执行与通信提供了基本的支持;
Go目标是要成为一种现在的系统语言,不过目前更多用来构建支持高性能高并发web服务。
  • 列出常用的一些built-int包
web server: /net/http
database: database/sql
compress: compress/gzip
cryptography: Crypto/md5, crypto/sha1
encoding: encoding/json
  • 如何理解goroutine? 如何停止一个goroutine?
goroutine是Golang实现并发的最小逻辑单元;
非常轻量级,是一段代码,一个函数入口,以及在堆上为其分配的一个堆栈;
是一种用户态线程,不被linux内核识别,运行在内核线程之上;
goroutine在cpu上换入换出,不断上下文切换的时候,必须要保证的事情就是保存现场和恢复现场。
可以通过设置信号channel来阻塞和退出一个goroutine。
  • 如果gorouting中有很多阻塞系统调用,那是不是会创建很多内核线程?
是的,处于等待系统调用中M不会占用mcpu数量, 只有在运行中的M才会占用mcpu数量并对应到一条系统线程。
sysmon线程会将进入系统调用的M上的G队列移到其他M上等待执行。
P(最开始只有G和M,Processor可看作是后来加入的一种优化)用于解决之前并发执行中加锁的性能问题, 是N1调度器转到M:N调度器的重要部分。
  • Go中的channel和mutex锁机制的比较
程序间通讯两种模型: 1)共享内存 2)消息传递
channel是消息传递在Go上的具体实现, 四个基本操作:打开/关闭/写/读channel。

channel与mutex重要区别: 一件任务是在“调用处”还是“被调用处”执行。

channel典型应用场景:一个goroutine负责处理某个任务或资源,其他goroutine通过channel向它发送相关指令。
mutex典型应用场景:goroutine访问一个共享资源前进行加锁,然后自己处理完相关操作后再释放资源。

channel会消耗更多成本,因为涉及到上下文切换;而mutex通常只是一个原子操作。

无法通过mutex控制并发的goroutine数量, 但是可以通过带缓存的channel来指定并发goroutine数。
  • Go中的数组和C中的数组有什么区别?
1. Go中数组是值类型,数组赋值给另一个变量会对所有元素进行拷贝;
2. 向函数传递数组参数,传递的是该数组的拷贝而不是指针;
3. 数组的长度也是数组类型的一部分,[2]int和[4]int是两种不同的类型。
  • 谈谈Go中的接口?
接口可以看作是一种对象的行为集合,一系列函数的集合;
要实现一个接口,需要实现该接口中的所有方法;
实现接口是非侵入式的,去掉复杂继承体系。
interface具体数据结构:
struct Eface    // 空interface
{
    Type*    type;
    void*    data;
};

struct Iface    // 带方法的interface
{
    Itab*    tab;
    void*    data;
};
  • 谈谈Go中的类型转换和类型断言?
普通类型转接口类型是隐式的,接口类型转普通类型需要进行类型断言;
类型断言前一般要做些判断,避免panic: value, ok := a.(string)
  • 谈谈Go中的闭包?
闭包:函数+引用变量, 引用变量是不能在栈上分配的;
逃逸分析:go编译器可以分析出变量的作用范围,自动决定是在栈还是对分配内存,将闭包环境变量在堆上分配是Go实现闭包的基础;
结构体:返回闭包并不仅仅是返回一个函数,而是返回一个结构体,包含函数返回地址和所引用环境的变量地址等信息。
  • Go中实现非阻塞IO的原理是怎样的
在Go程序初始化时, 会启动一个后台线程sysmon(主要角色称为poller)。
当某个goroutine进行IO操作而此刻IO还没准备好,那它就会被放到等待队列中,
此时该goroutine被阻塞了,但系统继续运行其他goroutine。

这样,所有发生阻塞的文件描述符fd会添加到这个poller上,
而poller不停的进行poll,一旦获取到就绪的fd描述符,
就会唤醒之前因它而阻塞的goroutine   。

poller比gc更高级,前者是一个物理线程,而后者只是线程池里的一个goroutine任务。
  • 关于Go中的栈管理技术(分段栈和连续栈)
分段栈: 
Go1.4之前的栈管理技术,运行时给每个goroutine分配8K的初始化栈内存;
在每个go函数之前有个代码块,检查已分配栈空间已不足,
不足的话会调用morestack函数来分配一段新的内存作栈空间,
然后将包括上一个栈地址等信息的struct和lessmore函数写入栈底,
接着重启gorouine,从将原来栈空间用光的函数开始执行(这里称为stack split)。
等该函数执行返回时,通过lessstack函数查找栈底部struct来调整栈指针,
使得返回原来栈空间,同时将该新栈段释放掉。
连续栈:
Go1.4之后使用连续栈,同样在每个函数入口进行栈溢出检查,
只是在栈溢出时会申请一个两倍于当前栈空间的内存空间,
然后把当前旧栈拷贝到新栈,释放旧栈空间,
最后程序重启goroutine并从引起重新分配栈段的函数继续执行。
实现栈拷贝的关键:
1. 只有在栈上分配的指针才能指向栈上的地址;
2. 需要知道栈上哪部分是指针,因为移动栈时需要把所有的指针指向新的目标地址;
原来Go运行时很多是C写的,大量运行时调用没有指针信息可用,这也是Go runtime被大规模重构的主要原因。
  • 关于Go的内存池
Go 初始化时申请一大块的虚拟内存空间,所有对象的内存回收时不会释放虚拟地址空间,但是虚拟地址空间和物理内存的映射会还给操作系统。
如果系统还有空余空间,这些物理内存暂时就先留着给 Go 使用,避免频繁分配内存;当系统真正需要时则可以则回收这部分内存。

其参考tcmalloc,分级内存池管理,几个关键数据结构:
- mspan
由mheap管理的页面,记录了所分配的块大小和起始地址等
- mcache
与P(可看做cpu)绑定的线程级别的本地缓存
- mcenter
全局空间的缓存,收集了各种大小(67种)的span列表
- mheap
分配内存的堆分配器,以8kb进行页管理
- fixalloc
固定尺寸的堆外(直接由系统管理的内存)对象空闲列表分配器,用来管理分配器的存储
  • 浅谈Go的垃圾回收机制
常见算法: 引用计数,标记清扫, 三色标记清扫,分代回收
Go1.5后至目前主要用了并发三色标记清扫算法,有效减少停顿时间。
垃圾回收触发:由一个gcpercent变量控制,比如gcpercent=100,
假设当前使用内存=100M,那么等到使用内存分配达到200MB时将触发GC;假设GC后的内存回到了120MB,那下次触发GC将在分配内存达到240MB的时候。
  • golang中如何阻塞等待所有goroutines都完成
package test

import (
    "fmt"
    "runtime"
)

// 方法1:使用sync锁机制
func ch_worker(index int, ch *chan int) {
    fmt.Printf("ch_worker, current index: %d\n", index)
    *ch <- 1
}

func Test_Channel() {
    num := runtime.NumCPU()
    ch := make(chan int, num)

    for i := 0; i < num; i++ {
        go ch_worker(i, &ch)
    }

    for j := 0; j < num; j++ {
        <-ch
    }
}

// 方法2:利用channel阻塞机制
func wg_worker(index int, w *sync.WaitGroup) {
    defer w.Done()
    fmt.Printf("current index: %d\n", index)
}

func Test_WG() {
    num := runtime.NumCPU()
    var w sync.WaitGroup
    for i := 0; i < num; i++ {
        w.Add(1)
        go wg_worker(i, &w)
    }
    w.Wait()
}
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值