工作用Go: 异步任务怎么写3 | 避坑: 野生 Goroutine

简介: 工作用Go: 异步任务怎么写3 | 避坑: 野生 Goroutine

go01.jpeg

本文为 工作用Go: 异步任务怎么写 系列的第3



在继续讲解之前, 一定要提一下使用 go 开协程的一个, 或者说一个非常重要的基础知识:


Go基础知识: panic只对当前goroutine的defer有效


Go中出现 panic(), 程序会立即终止:

funcTestPanic(t*testing.T) {
panic("panic")
log.Print("end")
}
=== RUN   TestPanic
--- FAIL: TestPanic (0.00s)
panic: panic [recovered]
 panic: panic
goroutine 118 [running]:
testing.tRunner.func1.2({0x103e15940, 0x10405c208})
 /opt/homebrew/opt/go/libexec/src/testing/testing.go:1396 +0x1c8
testing.tRunner.func1()
 /opt/homebrew/opt/go/libexec/src/testing/testing.go:1399 +0x378
panic({0x103e15940, 0x10405c208})
 /opt/homebrew/opt/go/libexec/src/runtime/panic.go:884 +0x204
pkg.poizon.com/ee/ehr/tests/util.TestPanic(0x0?)
 /Users/dayday/dw/ehr/tests/util/pkg_test.go:34 +0x2c
testing.tRunner(0x14000603040, 0x104058678)
 /opt/homebrew/opt/go/libexec/src/testing/testing.go:1446 +0x10c
created by testing.(*T).Run
 /opt/homebrew/opt/go/libexec/src/testing/testing.go:1493 +0x300
Process finished with the exit code 1


  • 可以看到, panic 后程序直接退出, panic 后的 log.Print("end") 并没有执行


当然, 想要程序健壮一些, panic 是可以 吃掉 的:

funcTestPanic(t*testing.T) {
deferfunc() {
ifr :=recover(); r!=nil {
log.Print(r)
  }
 }()
panic("panic")
log.Print("end")
}
=== RUN   TestPanic
2022/11/17 22:25:08 panic
--- PASS: TestPanic (0.00s)
PASS


使用 recover()panic() 进行恢复, 程序就不会崩掉(exit)


但是, 一定要注意

panic只对当前goroutine的defer有效!

panic只对当前goroutine的defer有效!

panic只对当前goroutine的defer有效!

重要的事情说三遍.

funcTestPanic(t*testing.T) {
deferfunc() {
ifr :=recover(); r!=nil {
log.Print(r)
  }
 }()
gofunc() {
panic("panic")
 }()
log.Print("end")
}
===RUNTestPanicpanic: panicgoroutine88 [running]:
pkg.poizon.com/ee/ehr/tests/util.TestPanic.func2()
/Users/dayday/dw/ehr/tests/util/pkg_test.go:41+0x2ccreatedbypkg.poizon.com/ee/ehr/tests/util.TestPanic/Users/dayday/dw/ehr/tests/util/pkg_test.go:40+0x40Processfinishedwiththeexitcode1


而 go 里面开协程又是如此的方便, 简单一个 go 关键字即可, 所以大家给这种情况起了个外号: 野生 Goroutine. 最简单的做法就是对协程进行一次封装, 比如这样:

packagegox// Run start with a goroutinefuncRun(fnfunc()) {
gofunc() {
deferfunc() {
ifr :=recover(); r!=nil {
log.Print(r)
   }
  }()
fn()
 }()
}

原本的 go task(), 使用 gox.Run(task)进行替换, 就可以 task 出现 panic 的时候, 程序还能恢复

目录
相关文章
|
2月前
|
安全 Go 数据处理
Go语言中的并发编程:掌握goroutine和channel的艺术####
本文深入探讨了Go语言在并发编程领域的核心概念——goroutine与channel。不同于传统的单线程执行模式,Go通过轻量级的goroutine实现了高效的并发处理,而channel作为goroutines之间通信的桥梁,确保了数据传递的安全性与高效性。文章首先简述了goroutine的基本特性及其创建方法,随后详细解析了channel的类型、操作以及它们如何协同工作以构建健壮的并发应用。此外,还介绍了select语句在多路复用中的应用,以及如何利用WaitGroup等待一组goroutine完成。最后,通过一个实际案例展示了如何在Go中设计并实现一个简单的并发程序,旨在帮助读者理解并掌
|
2月前
|
安全 Java Go
Go语言中的并发编程:掌握goroutine与通道的艺术####
本文深入探讨了Go语言中的核心特性——并发编程,通过实例解析goroutine和通道的高效使用技巧,旨在帮助开发者提升多线程程序的性能与可靠性。 ####
|
2月前
|
安全 Go 调度
探索Go语言的并发模型:goroutine与channel
在这个快节奏的技术世界中,Go语言以其简洁的并发模型脱颖而出。本文将带你深入了解Go语言的goroutine和channel,这两个核心特性如何协同工作,以实现高效、简洁的并发编程。
|
2月前
|
Go 调度 开发者
探索Go语言中的并发模式:goroutine与channel
在本文中,我们将深入探讨Go语言中的核心并发特性——goroutine和channel。不同于传统的并发模型,Go语言的并发机制以其简洁性和高效性著称。本文将通过实际代码示例,展示如何利用goroutine实现轻量级的并发执行,以及如何通过channel安全地在goroutine之间传递数据。摘要部分将概述这些概念,并提示读者本文将提供哪些具体的技术洞见。
|
2月前
|
安全 Go 调度
解密Go语言并发模型:CSP与goroutine的魔法
在本文中,我们将深入探讨Go语言的并发模型,特别是CSP(Communicating Sequential Processes)理论及其在Go中的实现——goroutine。我们将分析CSP如何为并发编程提供了一种清晰、简洁的方法,并通过goroutine展示Go语言在处理高并发场景下的独特优势。
|
3月前
|
安全 Go 调度
探索Go语言的并发之美:goroutine与channel
在这个快节奏的技术时代,Go语言以其简洁的语法和强大的并发能力脱颖而出。本文将带你深入Go语言的并发机制,探索goroutine的轻量级特性和channel的同步通信能力,让你在高并发场景下也能游刃有余。
|
7月前
|
Go
go的并发初体验、加锁、异步
go的并发初体验、加锁、异步
|
3月前
|
存储 安全 Go
探索Go语言的并发模型:Goroutine与Channel
在Go语言的多核处理器时代,传统并发模型已无法满足高效、低延迟的需求。本文深入探讨Go语言的并发处理机制,包括Goroutine的轻量级线程模型和Channel的通信机制,揭示它们如何共同构建出高效、简洁的并发程序。
|
3月前
|
存储 Go 调度
深入理解Go语言的并发模型:goroutine与channel
在这个快速变化的技术世界中,Go语言以其简洁的并发模型脱颖而出。本文将带你穿越Go语言的并发世界,探索goroutine的轻量级特性和channel的同步机制。摘要部分,我们将用一段对话来揭示Go并发模型的魔力,而不是传统的介绍性文字。
|
3月前
|
安全 Go 调度
探索Go语言的并发模型:Goroutine与Channel的魔力
本文深入探讨了Go语言的并发模型,不仅解释了Goroutine的概念和特性,还详细讲解了Channel的用法和它们在并发编程中的重要性。通过实际代码示例,揭示了Go语言如何通过轻量级线程和通信机制来实现高效的并发处理。