曹大可以卷一下for range的底层实现吗
- 在 http://golang-ssaview.herokuapp.com/ 上依次看各种 for range 的翻译结果就好了
关于goroutine的退出,只能侵入式的在函数里面调用goexit()吗,比如go func test(),想把test作为一个黑盒来看,像java一样从外部中断它,是不是没有办法?
- 不行,只能 ctx,select ctx.Done()
- sigurg,runtime 1.14,用户代码中无法使用
能讲一下g、m、p、schedt这几个类型中主要字段的含义么
- schedt 全局调度结构,记录全局队列、空闲 m 列表、空闲 p,一些高频分配释放的结构的缓存
曹大可以分享下之前在蚂蚁遇到的调度方面的一些坑和解决方案吗
- https://xargin.com/schedule-when-holding-lock-causes-latency-spike/
- continuous profiling
为什么这段代码会执行两次chansend和closechan(chansend -> closechan -> close(ch) ->closechan -> (ch <- 4) ->chansend), 以及第一次chansend中的dataqsize=2
- skip…
1
2
3
4
5
6
7
8
9
10
11
12
13package main
import "time"
func main() {
var ch chan int
ch = make(chan int)
close(ch) # 断点
go func() {
time.Sleep(1 * time.Second)
ch <- 4 # 断点
}()
time.Sleep(2 * time.Second)
}
chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) 参数的block是啥含义 non blocking select, block = false
1 | select { |
gopark是操作的内存让g切换的么
- gopark -> send block -> put curg -> ch sendq,操作 g 让 用户代码中阻塞的 g 进等待队列。
- 线程执行 schedule 进下一轮调度循环
golang中为什么要有goto,是因为比循环快么?
- 猜测是几个主要作者是 C 的作者,C 语言中用的最多的两个 goto 场景:
- goto handle_error
- gotoretry
调用parser.ParseExpr(“a op b”),a和b的解析结果为什么不一样,操作符op前的字符串解析的Kind总是bad,但操作符前的数字就能成INT或FLOAT
- 得看 ParseExpr 的源代码了
- 支持更多操作符的话,在 Go 里最好还是要用 goyacc 之类的生产级解决方案:https://github.com/cch123/parser_example
可以参考 vitess、sqlflow 等项目中的简单的 SQL parser对于八核心的CPU,如果有7个M在被syscall/cgo阻塞住,这个时候多少任务都会用一个P了么?
- syscall 阻塞 M 和 P 会在 sysmon 里解绑定,P 空闲,可以创建新的 M 配对
能不能介绍一些cgo, gobpf
- cgo 不会涉及
- ebpf 在优化中可能会有
channel的接受队列和发送队列有大小限制么?
- 链表结构,你说呢~
runtime.ready()的最后一个参数next为啥只有gc调用的时候才是false,就两个优先级么
- 放问答区吧
前段时间遇到个偶发的oom,大概的情况是goruntine里面有一个mysql事务,因为疏忽,某种情况下return error时忘了 rollback,造成事务一直卡在那里(超时时间好像是1年😂),一段时间后,触发次数多了,更多的事务卡住了,数据库连接也不够了,然后突然内存暴涨(原因也不清楚😂),像这种类似的事故曹大有什么经验分享吗?
- https://github.com/mosn/holmes
- https://xargin.com/continuous-profiling/
- https://www.google.com/search?q=continuous+profiling&sxsrf=ALeKk00cD5mXb_nGnEGcIibVHOvheexNyw%3A1621691923881&source=hp&ei=Ew6pYLT5MvHM0PEP0c-9-Ak&iflsig=AINFCbYAAAAAYKkcIx7cSwcEOMY1yXWBeDUUgUvYR3oQ&oq=continuous+profiling&gs_lcp=Cgdnd3Mtd2l6EAMyBAgjECcyBQgAEMsBMgUIABDLATIFCAAQywEyBQgAEMsBMgUIABDLATIFCAAQywEyBAgAEB4yBAgAEB4yBAgAEB46AggAOgYIIxAnEBM6BwgAEAoQywE6BwgjELECECdQtQFY8j5gj0FoDnAAeACAAeUCiAHUOZIBBjItMjQuM5gBAKABAaoBB2d3cy13aXo&sclient=gws-wiz&ved=0ahUKEwj0zriYud3wAhVxJjQIHdFnD58Q4dUDCAc&uact=5
曹大 目前Go的一些汇编的实现 从哪里可以简单学习下这些语法呢
- https://github.com/cch123/golang-notes/blob/master/assembly.md,文章里的参考链接可以看看
- https://colobu.com/goasm/,里面的例子值玩一玩
https://go.googlesource.com/proposal/+/master/design/40724-register-calling.md曹大应该看过这篇文章了,能说说您的看法吗?
- 官方做这套方案并没有打算兼容其它语言的 ABI,感觉主要还是为了优化一些速度
- 感觉没啥特别的
cpu可绑定goroutine运行吗?taskset?,什么场景适合多线程,什么场景适合goroutine?
- 应该控制不了这么细的粒度,taskset 只能绑核心,cpu_set_affinity 在 Go 内部用不了吧。
- CPU 密集型用,bcrypt 类的服务,用 Go 非常不合适,因为公平调度可能导致大量超时。公司场景一般会选择用 c++ 或 Rust 重写这类服务。
源码有两个地方可能出现send on closed channel,一个是在发送的时候,一个是在goroutine因为channel而阻塞后,然后被唤醒在判断的,唤醒后的这种情况不是很明白, 曹大可以讲下么(在chan.go的258行)?
- 问答区见
g读和写为nil的chan,陷入阻塞住的话,怎么把它唤醒?会彻底死住吗?是sysmon处理吗? 唤醒不了,就是永远阻塞了
曹大可以讲下用ast的解析sql转es吗?大概流程,goyacc是啥
![]()
- goyacc 是一个 parser 生成工具,写 grammar.y 文件,生成你的 parser 代码。
一个工程问题,公司测试team在跑长稳测试时,出现了一些不容易复现的功能问题(如不可用),但是通过走读代码去排查的时候,发现依赖的是三方库(去做的一些文件读写和内存读写)。所以想请教下曹大,在针对长稳测试中的偶现问题,有什么较好的pratice去闭环这种问题
- ABI 兼容部分 : lua 可以和 c c++ 互操作 也是以 ABI兼容 为必要条件的吧
- lua 是用 C++ 实现了它的 vm,lua 跑在 vm 上解释执行
- ABI 兼容说的应该是二进制之间可以互相调用,例如用 A 语言提供动态链接库 .so,B 语言可以直接使用
能讲下golang 的内联优化吗,我看你在视频中会禁用它去调试?
- inline //go:noinline 可以关闭内联,用 gcflags=”-l” 也可以关闭内联,这是一个通用的编译优化概念
- 执行时,将被调用的函数原地展开:main() { add() } add() { return x + y} => main() { x + y }
go 是从1.14实现的自举吗,cgo底层就是调用一些寄存器吗,是否还会调用c代码
- 1.4, 1.5 左右就实现了,用 Go 编译 Go 本身
- cgo 指的是 go call c 或者 c call go,两个方向都是可以的,除了一些视频相关的领域,应该使用场景不多(还有一些场景是为了优化,例如用 cgo 来做堆外内存管理)
编译原理没系统性学习过的话,看go这块的汇编代码如果想看的比较舒服,要补齐那些东西嘞?
- 汇编代码应该是体系结构的内容吧,看看我写的这个应该就简单入门了:https://github.com/cch123/golang-notes/blob/master/assembly.md,想要深入了解点得找本书看看
- 编译原理是另一块,课上推荐了几本书:crafting interpreters,interpreterbook, compilerbook,可以随便挑两本,感兴趣了再深入
后面会讲context原理么
曹大能介绍下一些跟课程相关的黑科技工具,例如gomonkey 这种patch的黑科技,怎么做到运行时替换函数的
- 运行时替换 .text 段里的内容实现的,在头部 jmp -> to 你自己定义的函数
- monkey patch 不是很新的技术,在 linux kernel 领域有 hot patch 一说,原理是一样的
golang编程的话,遇到异步任务,是直接启动一个goroutine呢,还是使用一个goroutine池呢,像线程池那样? 看好些人的代码都是直接启动一个goroutine
- 起 goroutine,碰到问题再优化
- 要会压测
- fasthttp workerpool,减少 goroutine 频繁创建,一定程度上降低 runtime.schedule CPU 占用
golang 创建多少线程,是怎么决定的?一直都是讲Goroutine,底层线程什么时候会创建。创建多少?什么时候会复用。
- schedule 循环的 M 大致上 = P 的数量
- 当 M 阻塞在 syscall/cgo,有新的任务和空闲的 P,需要补足线程
- 详情可以问答区说
go 1.14新增抢占后,官方文档提示需要自己手动处理syscall EINTR,请问曹大有遇到这个的例子么?
- 要去查一下
- 问答区说吧
如何提高某个goroutine 的优先级?譬如有个goroutine做分派任务的,需要保证它的CPU 片,它的优先级应该比worker高得多
- Go 的 goroutine 没有优先级,公平调度,所以在碰到需要优先级的场景时,会遇到问题
- https://www.zenlife.tk/go-scheduler-pitfall.md,这是 pingcap 工程师举的一个例子
- 某些公司会修改 Go 的 runtime,来提供高优先级的 goroutine 创建接口
曹大,假设我有一个接口需要提供数据,但这些数据需要查询多个数据库里面的n个表才能查得,需要开上百个goroutine并发查,请问有什么好建议?
- 感觉 db 扛不住,建议压测试试
执行 test 过程中,某些用例run test 不可以通过,debug就可以通过,有什么排查方向吗?用的goconvey写的test,就是有些 monkey patch的函数不生效
1 | go test -gcflags=-l |
- 可能你忘了带gcflags了
刚刚那个bcrypt性能问题,最终是把整个服务用c++重写?还是把那部分模块抽出来,然后和之前的Go做grpc之类的调用?
- 重写接口,C++
//go:nosplit 和原子操作有关么?
- nosplit 当前栈不会扩展,所以不需要插入函数头栈检查指令
- 和原子操作没啥关系。。
对于海量的goroutine场景中,当一个goroutine拿着锁还没释放,时间片到了,就被sysmon调走了,放倒全局队列或P的本地队列,这种情况怎么解决?
- 问答区见
线上程序的偶发性问题是不是可以打dump文件分析?类似这种会讲么?
- goroutine、mem 使用、CPU 使用触发主动 profile dump
- continuous profiling,curl debug/pprof?debug=1
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 lihuanjie113@gmail.com