当前位置: 首页 > 科技观察

Go有哪些不可恢复的致命场景?

时间:2023-03-11 21:51:53 科技观察

大家好,我是炸鱼。在事故现场,紧急恢复后,他正在检查代码很长时间。回头一看,这个报错信息明显是致命错误,还是定位一下比较好。但是这个时候他居然在检查panic-recover是不是少了,吓我一跳……今天建宇就给大家分享一下错误的类型以及触发的场景。错误类型error第一种是Go中最标准的错误error,其实就是一个interface{}。如下:typeerrorinterface{Error()string}在日常工程中,我们只需要创建任意一个结构体,实现Error方法,就可以认为是错误类型。如下:typeerrorStringstruct{sstring}func(e*errorString)Error()string{returne.s}对外调用标准库API,一般如下:f,err:=os.Open("filename.ext")iferr!=nil{log.Fatal(err)}//dosomethingwiththeopen*Filef我们会约定最后一个参数是error类型,一般常见于第二个参数,可以有习惯。第二种panic是Go中的异常处理panic,可以产生异常错误,结合panic+recover可以逆转程序的运行状态。如下:packagemainimport"os"funcmain(){panic("aproblem")_,err:=os.Create("/tmp/file")iferr!=nil{panic(err)}}输出结果:$gorunpanic。gopanic:aproblemgoroutine1[running]:main.main()/.../panic.go:12+0x47...exitstatus2如果不使用recover作为捕获,程序就会中断。因此,人们常常误认为程序中断100%是恐慌造成的。这是一种误解。第三种throw是Go初学者经常踩到不知道的一类错误,也就是致命错误throw。此类错误无法在用户端主动调用。它由Go本身的底层调用。比如常见的map的并发读写就是由此触发的。其源码如下:functhrow(sstring){systemstack(func(){print("fatalerror:",s,"\n")})gp:=getg()ifgp.m.throwing==0{gp.m.throwing=1}fatalthrow()*(*int)(nil)=0//notreached}根据上面的程序,会得到G的当前实例,并将其M的throwing状态设置为1。之后状态已设置,将调用fatalthrow方法来执行真正的崩溃相关操作:ifdopanic_m(gp,pc,sp){crash()}exit(2)})*(*int)(nil)=0//notreached}主要逻辑是发送_SIGABRT信号量,最后调用exit方法来退出,所以你会发现这是一个无法停止的“致命”错误。致命场景为此,作为一个“成熟”的Go工程师,除了保证自己程序的健壮性,我也在网上收集了一些致命错误场景,分享给大家。一起学习并避免这些致命的情况,以在年底获得A为目标,不要背上P0事故。并发读写mapfuncfoo(){m:=map[string]int{}gofunc(){for{m["炸鱼1"]=1}}()for{_=m["炸鱼2"]}}输出结果:fatalerror:concurrentmapreadandmapwritegoroutine1[running]:runtime.throw(0x1078103,0x21)...stackmemoryexhaustedfuncfoo(){varffunc(a[1000]int64)f=func(a[1000]int64){f(a)}f([1000]int64{})}输出:runtime:goroutinestackexceeds1000000000-bytelimit/go/1.16.6/libexec/src/runtime/panic.go:1117+0x72runtime.newstack()。..startfuncfoo(){varffunc()gof()}withnilfunction作为goroutine输出:fatalerror:goofnilfuncvaluegoroutine1[running]:main.foo()...goroutinesdeadlockfuncfoo(){select{}}output:fatalerror:allgoroutinesareasleep-deadlock!goroutine1[select(nocases)]:main.foo()...threadlimitExhaustion如果您的goroutines被IO操作阻塞,则可能会启动新线程来执行您的其他goroutines。Go对最大线程数有一个默认限制,如果达到这个限制,你的应用程序就会崩溃。会出现如下输出:fataerror:threadexhaustment...可以通过调用runtime.SetMaxThreads方法增加线程数,但是也需要考虑是不是程序有问题。Exceedingavailablememory如果你执行如:下载大文件等操作,导致应用程序占用内存过多,程序上升,导致OOM。会出现如下输出:fataerror:runtime:outofmemory...建议处理掉一些程序,或者更换一台新电脑。总结在今天的文章中,我们介绍了Go语言中的三种错误类型。其中介绍了大家最不常见,但遇到容易翻车的致命错误,并给出了一些经典案例。我希望你以后能避免它。这些场景你遇到过吗?欢迎在评论区交流留言:)参考Go中所有的运行时错误都可以恢复吗?