挑几个来说
## 语言设计相关
> 3. defer 的概念非常有趣,也很符合 Go 的设计主旨,不知道 Go 语言中是否有类似 Python 中上下文管理器的工具(即实现打开文件时确保其使用后被关闭,上锁时确保使用后会开锁等操作)
既然知道 defer ,defer close/unlock 就可以了,不应该还有这种疑问。不同语言提供不同的东西,也没必要非得别人有啥就要 go 有同样的东西。
另外,比如 os.File 这种,即使不 defer close ,gc 时也会自动 close 、不至于泄露,只是可能不太及时,或者如果你的代码泄露了没有 defer 也没有 gc 才会副作用:
https://github.com/golang/go/blob/master/src/os/file_unix.go#L239> 4. 从原理角度,如何理解 channel 的调用开销。使用 channel 传递数据究竟是一种廉价操作,还是昂贵操作,其究竟是否依赖锁?按我的理解它依赖于事件循环,每次激活后才会唤醒依赖它的协程,应该是无锁的,但是书里写它其实是有锁的,我不是很懂。
直接看源码吧,也可以配合一些别人的文章来看源码,比这种问答要认识的更清晰:
https://github.com/golang/go/blob/master/src/runtime/chan.go#L160https://github.com/golang/go/blob/master/src/runtime/chan.go#L4575. 如果 channel 有锁,通道通信相较于内存共享的优越性体现在哪里?
channel 适合业务层简单逻辑:你把它当成进程内的消息队列就可以了,与锁的区别主要是带容量、可以把逻辑串行化并去锁,用于异步、解耦之类的比较好。但简单的队列数据结构同步,channel 性能是不如锁的、而且用锁可以在当前上下文继续进行剩下的穿行逻辑,放到 channel 后则需要其他地方去异步从护理了,未必就是 channel 方便。
性能需要的场景,比如基础设施领域,锁仍然是主力,不能被 channel 替代。
> 6. 对于 string 的处理方式。我们都知道 string 通常是比看上去更复杂的数据结构,教学视频中看到的所有赋值和参数调用基本都是直接传值,实际情况是否如此,这是否意味着如果不加优化通常效率会很低?
你说的 string 传值只是 string 结构体定义的这个小结构体:
https://github.com/golang/go/blob/master/src/runtime/string.go#L232并不是需要深拷贝 string 的 payload 然后再传值,所以相比于传指针开销并不算大
## 多线程调度相关
> 2. Go 的调度模型下,单个协程应该是很省的,但是如果我有一万个协程同时对一个 map 进行交互,此种情况下应该如何进行优化?(或者说 Go 应对此种场景时也并无特殊优势?)
1) 减小锁粒度:无非就是多加点 shard/bucket ,减小每个 map 元素数量,从而减小锁粒度
2) 提高并发度:1 )中处理后,就可以去多协程去搞每个 shard/bucket 的 foreach 了,典型的如广播场景,广播优化主要就几个点:避免写阻塞,降低锁粒度,提高并发度,批次发送
## 最佳实践相关
> 1. 通常情况下,Go 语言调查未知对象内部属性和方法的最佳实践是什么?
设计者应该根据需要设计数据结构,除了三方互接并且对方乱搞,为什么一定要依赖调查?绝大多数正常的业务领域,脑子拧巴的实现者才喜欢去猜、让自己或者让别人用奇淫巧计去实现需求
避免使用反射。
那些不理解甚至嘲讽 go 的大道至简的人,其实就是花了很多时间学会了很多其他语言的奇淫巧计,沉没成本效应,让这部分人舍不得放弃以前学的那些糟粕思维,然后惯性地用那些思维来思考 go ,然后才会有这些垃圾问题和需求。当然,我不否认少数时候 go 里也需要奇淫巧计,我自己也用。
其他问题好像多数偏于垃圾问题,不答了