golang

使用Golang时遇到的一些坑

好久不见. 提交于 2019-12-05 00:21:32
1、 【致命】不是所有Panic都能捕获 我们知道Golang给开发人员提供recover()机制,对堆栈异常(panic)进行捕获并自定义其处理逻辑。下面举个例子: 构造一个除0的异常场景: 输出结果: 我们看到程序正常退出,没有异常,说明recover()按照预期捕获到panic异常;但不是所有panic都能通过recover()捕捉到的,比如:并发操作map实例。 构造并发操作map的场景: 输出结果: 以上结果可知,我们不能单纯依靠recover()解决函数内部所有panic异常,应该做到以下几点: a) 通过编写代码校验,防止能预期到的panic,比如:空指针引用的指针判断。 b) 对于无法预期的panic,使用recover()捕获并加以处理。 c) 使用map时,必须要考虑是否存在并发读写场景,存在时,应使用ConcurrentMap组件或自己加sync.RWMutex进行加锁保护。 相关参考: 关于并发读写map导致的panic无法使用recover()捕获,是Go1.6增加的一个特性,https://golang.org/doc/go1.6#runtime; 当然这个并非是唯一一个无法通过recover()捕获的场景,还有可能Go本身的bug,https://github.com/golang/go/issues/21717;这个Bug在Go1.9.2才修复 2、

GOLANG的PANIC和RECOVER

若如初见. 提交于 2019-12-05 00:20:18
转载:http://0x55aa.sinaapp.com/%E7%AE%97%E6%B3%95-%E7%BC%96%E7%A8%8B/722.html http://www.cnblogs.com/ghj1976/archive/2013/02/11/2910114.html Go没有例如像Java那样的异常机制:不能抛出一个异常。作为代替,它使用了panic和recover机制。一定要记得,这应当作为最后的手段被使用,你的代码中应当没有,或者很少的令人恐慌的东西。这是个强大的工具,明智的使用它。那么,应该如何使用它。 Panic 是一个内建函数,可以中断原有的控制流程,进入一个令人恐慌的流程中。当函数F调用panic,函数F的执行被中断,但是F中的延迟函数会正常执 行,然后F返回到调用它的地方。在调用的地方,F的行为就像调用了panic。这一过程继续向上,直到发生panic的goroutine中所有调用的函 数返回,此时程序退出。恐慌可以直接调用panic产生。也可以由运行时错误产生,例如访问越界的数组。 Recover 是一个内建的函数,可以让进入令人恐慌的流程中的goroutine恢复过来。Recover仅在延迟函数中有效。在正常的执行过程中,调用 recover会返回nil,并且没有其他任何效果。如果当前的goroutine 陷入恐慌

golang panic的捕获

我怕爱的太早我们不能终老 提交于 2019-12-05 00:18:46
panic发生时, 会导致进程挂掉。为了处理panic, 可以使用recover捕获,然后处理。 下面以下标引用越界问题为例进行说明。 正常情况下,代码中如果出现下标越界,会直接触发panic, 导致进程挂掉。 例如下面的例子: package main import ( "fmt" ) func main() { fmt.Println( "start..." ) count := [] int {} fmt.Println(count [1 ]) fmt.Println( "1..." ) } output: start… panic: runtime error: index out of range goroutine 1 [running]: main.main() D:/work/go_exercise/t.go:29 +0xd4 recover的使用 进程crash后,无法再提供服务,必须设法避免。 Go语言中提供recover可以用于捕获panic。 当对某些代码质量问题存在疑问时,可使用recover进行异常处理。 另外,如果没有panic发生,调用recover会返回nil. package main import ( "fmt" ) func main() { defer func (){ if r := recover (); r != nil { fmt

golang捕获panic

跟風遠走 提交于 2019-12-05 00:18:15
golang当中panic的时候如果启动的goroutine比较多,刷的信息满屏都是,在终端工具上因为刷的信息太多,找不到前边的信息,因此很有必要程序自己捕获panic,并且将错误信息输出到文件当中,以便定位排查问题。 以下是一段捕获panic的代码 package main import ( "fmt" "os" "runtime/debug" "time" ) func PanicHandler() { exeName := os.Args [0 ] //获取程序名称 now := time.Now() //获取当前时间 pid := os.Getpid() //获取进程ID time_str := now.Format( "20060102150405" ) //设定时间格式 fname := fmt.Sprintf( "%s-%d-%s-dump.log" , exeName, pid, time_str) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒) fmt.Println( "dump to file " , fname) f, err := os.Create(fname) if err != nil { return } defer f.Close() if err := recover (); err != nil { f

Golang panic 打印堆栈信息

拥有回忆 提交于 2019-12-05 00:17:29
一. 缘起 程序进程后台运行 monitor 监控程序负责拉起程序 当因为逻辑问题导致后台进程挂掉时,不容易发现程序曾经挂过。 golang 可以通过 recover 捕获 error,并将 panic 时的堆栈打印到日志来定位问题。 $ tree panictest panictest ├── main. go └── panic └── panic . go 二. 代码 main.go package main import ( "fmt" "os" "./panic" ) func test() { defer func () { if e := recover (); e != nil { panic .PrintStack() os.Exit (1 ) } }() zero := 0 x := 3 / zero fmt.Println( "x=" , x) } func main() { test() } panic.go package panic import ( "fmt" "runtime" ) func PrintStack() { var buf [4096 ] byte n := runtime.Stack(buf[:], false ) fmt.Printf( "==> %s\n" , string (buf[:n])) } 三. 运行结果 $ go

Golang协程机制以及异常处理

女生的网名这么多〃 提交于 2019-12-05 00:17:16
golang之所有好用,是因为其将以前编程中常用的而且晦涩难用的异步任务以及信号机制,以傻瓜式的语法给封装了一层。接触了golang已经有一段时间了,现在回头再看一下golang的协程机制,顺便做个总结。 一. 协程机制 详情可查看这篇论文《 Golang协程调度器详解 》 系统内核可以理解成一个经验丰富的管家,能把以前无系统下的各种任务(包括各种异步任务同步任务)给处理的很得当。其基本思想就是建造了进程对象,让cpu在多进程下来回切换,却又让进程无法察觉。这种解决方案彻底将应用层编程给分离了出来。但是后来随着任务量的增加,人们发现频繁的切换进程会造成很多额外的消耗(内存表等进程资源的切换消耗),而随着任务量增加,这种问题尤为突出。于是人们又发明了线程(Thread),线程是基于进程下的多任务,多线程降低了因为系统的进程量,多线程可以共用进程资源,但是多线程的任务切换也离不开内核的上下文切换以及cpu的寄存器内容切换。 golang基于以上计算机成果,在线程上创造了异步任务的实现方法---协程 协程组成: 1. M(应用层调度器):进行协程间的任务调度 2. P(系统线程):决定了最大并发执行任务数,通过 GOMAXPROCS参数控制线程数 3. G(协程): 独立运行的基本单位 基本思想: 调度器 执行时会创建线程池,并把协程放到线程上执行,待协程到了触发点(协程退出

Golang从入门到精通(二十一):Golang错误处理之panic-recover

社会主义新天地 提交于 2019-12-05 00:16:57
Go 语言没有像 Java 和 .NET 那样的 try/catch 异常机制:不能执行抛异常操作。但是有一套 defer-panic-and-recover 机制。 Golang中引入两个内置函数panic和recover来触发和终止异常处理流程,同时引入关键字defer来延迟执行defer后面的函数。一直等到包含defer语句的函数执行完毕时,延迟函数(defer后的函数)才会被执行,而不管包含defer语句的函数是通过return的正常结束,还是由于panic导致的异常结束。你可以在一个函数中执行多条defer语句,它们的执行顺序与声明顺序相反。 panic介绍 当发生像数组下标越界或类型断言失败这样的运行错误时,Go 运行时会触发运行时 panic ,伴随着程序的崩溃抛出一个 runtime.Error 接口类型的值。这个错误值有个 RuntimeError() 方法用于区别普通错误。 panic 可以直接从代码初始化:当错误条件(我们所测试的代码)很严苛且不可恢复,程序不能继续运行时,可以使用 panic 函数产生一个中止程序的运行时错误。 panic 接收一个做任意类型的参数,通常是字符串,在程序死亡时被打印出来。Go 运行时负责中止程序并给出调试信息。 panic() 是一个内建函数,可以中断原有的控制流程,进入一个令人 panic (恐慌即Java中的异常)的流程中

Golang panic 异常捕获

徘徊边缘 提交于 2019-12-05 00:16:37
1. panic异常是伴随协程的,所以在做并发时也一定要在每一个协程中对panic进行捕获和处理 2. 单线程程序修改为并发操作是要格外小心,原来单线程下在request入口处一个panic异常处理就可以保证主程序不会因panic和宕机,现在每一个并发程序中都需要加上该异常处理。 2019-06-17 来源: CSDN 作者: ye_guoyun 链接: https://blog.csdn.net/ye_guoyun/article/details/92712437

Golang的Panic和Recover

故事扮演 提交于 2019-12-05 00:16:00
什么是 panic? 在 Go 语言中,程序中一般是使用错误来处理异常情况。对于程序中出现的大部分异常情况,错误就已经够用了。 但在有些情况,当程序发生异常时,无法继续运行。在这种情况下,我们会使用 panic 来终止程序。当函数发生 panic 时,它会终止运行,在执行完所有的defer函数后,程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前协程的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪(Stack Trace),最后程序终止。在编写一个示例程序后,我们就能很好地理解这个概念了。 在本教程里,我们还会接着讨论,当程序发生 panic 时,使用 recover 可以重新获得对该程序的控制。 可以认为 panic 和 recover 与其他语言中的 try-catch-finally 语句类似,只不过一般我们很少使用 panic 和 recover 。而当我们使用了 panic 和 recover 时,也会比 try-catch-finally 更加优雅,代码更加整洁。 什么时候应该使用 panic? 需要注意的是,你应该尽可能地使用错误,而不是使用 panic 和 recover。只有当程序不能继续运行的时候,才应该使用 panic 和 recover 机制。 panic 有两个合理的用例。 发生了一个不能恢复的错误

Golang中的panic和recover

笑着哭i 提交于 2019-12-05 00:15:17
func panic(interface{})和func recover() interface{}是Golang中用于错误处理的两个函数。 panic的作用就是抛出一条错误信息,从它的参数类型可以看到它可以抛出任意类型的错误信息。在函数执行过程中的某处调用了panic,则立即抛出一个错误信息,同时函数的正常执行流程终止,但是该函数中panic之前定义的defer语句将被依次执行。之后 该goroutine立即停止执行。 recover()用于将panic的信息捕捉。 recover必须定义在panic之前的defer语句中 。在这种情况下,当panic被触发时,该goroutine不会简单的终止,而是会执行在它之前定义的defer语句。 下面是一个简单的例子: package main import "fmt" import "math" func foo(a int) { defer fmt.Println("foo退出来了") defer func() { if r := recover(); r != nil { fmt.Printf("捕获到的错误:%s\n", r) } }() if a < 0 { panic("必须输入大于0的数") } fmt.Println("该数的方根为:", math.Sqrt(float64(a))) } func main() { var