go中 panicrecoverdefer机制

news2024/9/21 10:53:08

 go的defer机制-CSDN博客 

常见panic场景

  • 数组或切片越界,例如 s := make([]int, 3); fmt.Println(s[5]) 会引发 panic: runtime error: index out of range
  • 空指针调用,例如 var p *Person; fmt.Println(p.Name) 会引发 panic: runtime error: invalid memory address or nil pointer dereference
  • 过早关闭 HTTP 响应体,例如 resp, err := http.Get(url); defer resp.Body.Close(); if err != nil { return err } 会引发 panic: runtime error: invalid memory address or nil pointer dereference,因为如果 http.Get 出错,resp 可能是 nil
  • 除以零,例如 x := 0; y := 1 / x 会引发 panic: runtime error: integer divide by zero
  • 向已经关闭的 channel 发送或接收消息,例如 ch := make(chan int); close(ch); ch <- 1 会引发 panic: send on closed channel
  • 重复关闭 channel,例如 ch := make(chan int); close(ch); close(ch) 会引发 panic: close of closed channel
  • 关闭未初始化的 channel,例如 var ch chan int; close(ch) 会引发 panic: close of nil channel
  • 未初始化的 map,例如 var m map[string]int; m["key"] = 1 会引发 panic: assignment to entry in nil map

recover常用的场景

  • panic 只会触发当前 Goroutine 的 defer
  • recover 只有在 defer 中调用才会生效;
package main

import "fmt"

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()

    fmt.Println("Before panic")
    panic("Something went wrong")
    fmt.Println("After panic") // This line will not be executed
}

运行结果

Before panic
Recovered from panic: Something went wrong

defer,recover,panic,goroutine之间有什么联系呢

recover的作用域,recover在什么时候才会起作用

recover什么时候有效

recover未在defer内使用,是不会起任何作用

func main() {
	if r := recover(); r != nil {
		fmt.Println("Recovered from panic:", r)
	}
	fmt.Println("Before panic")
	panic("Something went wrong")
	fmt.Println("After panic") // This line will not be executed
}


结果

Before panic
panic: Something went wrong

goroutine 1 [running]:
main.main()
        /Users/alan/GolandProjects/design-patterns/main.go:11 +0x78

recover必须搭配defer使用

recover在defer内使用才会起作用

package main

import "fmt"

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()

    fmt.Println("Before panic")
    panic("Something went wrong")
    fmt.Println("After panic") // This line will not be executed
}

运行结果

Before panic
Recovered from panic: Something went wrong

recove的作用域

recover在父协程

举个例子,一般使用chan的时候都是要在发送测关闭chan,我们在接受者通过控制超时

让函数提前退出,子协程一秒钟后退出


func main() {
	test()
	time.Sleep(time.Second * 10)
}
func test() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered from panic:", r)
		}
	}()
	var ch = make(chan int)
	go get_data(ch)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	defer close(ch)
	select {
	case <-ch:
		return
	case <-ctx.Done():
		return
	}
}
func get_data(ch chan int) {
	time.Sleep(time.Second * 2)
	ch <- 1
}

结果

我们发现没有recover住panic,子协程在test方法调用退出后,发生了panic,导致整个程序panic挂掉

recover,panic同子协程

相同的例子我们,我们在引起panic的协程内进行recover,结果函数正常recover后程序正常退出

func main() {
	test()
	time.Sleep(time.Second * 10)
	fmt.Println("时间到了 主函数也溜了")
}
func test() {
	defer func() {
		fmt.Println("test:我先溜了")
	}()
	var ch = make(chan int)
	go get_data(ch)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	defer close(ch)
	select {
	case <-ch:
		return
	case <-ctx.Done():
		return
	}
}
func get_data(ch chan int) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered from panic:", r)
		}
	}()
	time.Sleep(time.Second * 2)
	ch <- 1
}

结果

正确使用close关闭chan

recover在同级函数作用域下起效

引用

Go 语言踩坑记——panic 与 recover | 小米信息部技术团队

Go 语言 panic 和 recover 的原理 | Go 语言设计与实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2069206.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IT 人员配置的演变趋势:2024 年上半年的见解

随着我们深入研究 2024 年的动态格局&#xff0c;IT 人员配置领域在前六个月见证了几个值得注意的趋势和变化。 这些发展不仅反映了企业不断变化的需求&#xff0c;也凸显了技术对劳动力动态的变革性影响。 以下是在这个关键年份上半年塑造 IT 人员配置的一些关键趋势的详细介…

Python办公自动化smtplib实现自动发送邮件

学好python自动化&#xff0c;走遍天下都不怕&#xff01;&#xff01; 今天主要学习如何利用python自动化分析处理数据并以附件形式发送邮箱。需要安装配置python的运行环境&#xff0c;以及电脑支持Excel文件&#xff0c;有可以正常使用的邮箱。还需要用到python的第三方模块…

剧本杀门店预约小程序,提高消费者体验

当下&#xff0c;剧本杀行业一直处于活跃的状态&#xff0c;不管是线下聚会还是休闲娱乐&#xff0c;剧本杀游戏都是消费者的选择&#xff0c;剧本杀市场具有非常大的发展前景。 剧本杀门店预约系统是一个高效、便捷的游戏预约方式&#xff0c;能够帮助消费者便捷预约&#xf…

基于ssm的爱心捐赠管理系统的设计与实现(论文+源码)_kaic

摘 要 在互联网高速发展的现在&#xff0c;许多的办公与应用从传统的实体办理变为了在线处理。网购与网淘商品的浏览也从大街小巷变为了在线预览&#xff0c;从而使网上用户更好地对物品产生客观、全面立体的认知&#xff0c;并且对物品的对比也更加的省时省力。 爱心捐赠管…

一个简单的springboot项目(有源码)

开发一个springboot项目 代码迭代整合工具 gitee建模意义程序处理方式开发功能的步骤web服务网络状态码 web应用的开发分层springboot的作用 springboot框架搭建框架中各组件作用框架的演变如何提取hive中的表结构创建springboot 工程的引导模版 要选择aliyun &#xff0c;否则…

java ssl使用自定义证书或忽略证书

1.证书错误 Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 2.生成客户端证书 openssl x509 -in <(openssl s_client -connect 192.168.11.19:8101 -prexit 2>/dev/null) -ou…

linux neo4j 切换知识图谱

neo4j 安装 linux neo4j的安装可以浏览这篇文章&#xff1a; ubuntu sudo apt-get install neo4j 配置安装与设置远程访问 引言 如果你是window用户&#xff0c;直接下载桌面版进行安装与使用即可&#xff1b; 我有一台linux的服务器&#xff0c;想部署在上面&#xff0c;不…

UE5.4内容示例(5)UI_CommonUI - 学习笔记

https://www.unrealengine.com/marketplace/zh-CN/product/content-examples 《内容示例》是学习UE5的基础示例&#xff0c;可以用此熟悉一遍UE5的功能 UI_CommonUI可以看这个视频学习&#xff0c;此插件处于Beta状态&#xff0c;应用UI游戏方面&#xff0c;支持手柄等多输入端…

打饭-GYM

打饭 我还不信了&#xff0c;手动模拟一遍 再来了好看一点的图 ji12345a[i]21341120x3f0x3f0x3f0x3f0x3f114220x3f0x3f0x3f0x3f103520x3f0x3f0x3f0x3f9min(332,42)4020x3f0x3f0x3f8min(332,35)min(332,40)3190x3f0x3f7min(262,33)332490x3f0x3f6min(172,33)3120x3f0x3f0x3f5min…

【前端基础篇】JavaScript基础介绍

文章目录 前言初始JavaScriptJavaScript是什么发展历史JavaScript和HTML和CSS之间的关系JavaScript的运行过程JavaScript的组成 JavaScript的书写形式行内式内嵌式外部式注释 输入输出基础语法变量数据类型 运算符 JavaScript对象对象new关键字 常用对象数组创建数组数组操作函…

电影票api接口对接开发过程中需要注意什么?

电影票API接口对接过程需要考虑以下几个关键点&#xff1a; 1.了解API接口基础&#xff1a; 获取接口文档&#xff0c;理解其结构、请求方式、参数和返回数据格式。 2.接入流程&#xff1a; 使用API密钥或令牌进行身份验证。利用沙箱环境无风险测试。选择合适的编程语言实现…

Centos LVM磁盘合并方法

Centos LVM磁盘合并方法 使用fdisk -l命令查看机器增加了2块物理磁盘&#xff0c;一块40G另一块50G 需要将这两块盘的空间合并在一起&#xff0c;而且还需要动态扩展即在不关机的情况下操作 使用pvcreate将两块新增的物理磁盘加入物理卷 [rootlocalhost ~]# pvcreate /dev/sdb…

6G网络的关键技术、应用前景与挑战并存的科技征途

移动通信技术正以前所未有的速度迭代更新&#xff0c;而6G技术的研发与商用化进程渐渐成为了当前科技领域的热点与焦点。在5G技术尚未完全普及的今天&#xff0c;全球各国已纷纷将目光投向了更加充满想象的6G网络时代。本文将探讨全球6G研发的最新进展&#xff0c;特别是欧盟与…

Webots与ROS1、ROS2接口变迁-2024-

三大免费仿真器CoppeliaSim、Gazebo和Webots。 Gazebo接口总结&#xff1a; Gazebo与ROS1、ROS2接口变迁-2005-2024--CSDN博客 缺点&#xff1a;版本绑定策略 早期webots版本和ros版本绑定 后期&#xff0c;webots接口最新版本和ros特定版本最匹配。 例如&#xff1a; 最好按…

Ubuntu 中 SSH 服务的配置与原理详解

目录 1. 基本知识2. 配置步骤 1. 基本知识 一种用于在不安全的网络上安全登录和执行命令的协议 通过加密的方式保护通信数据&#xff0c;确保在传输过程中不被窃取或篡改 SSH 常用于远程登录服务器、传输文件以及执行命令 SSH 原理 公钥和私钥&#xff1a;SSH 使用公钥加密来…

UEFI 01记: 开发环境 在 ubuntu22 中搭建 edk2 开发环境并运行简单示例

https://uefi.org 1&#xff0c;预备环境 $ sudo apt install uuid-dev $ sudo apt install nasm $ sudo apt install bison flex $ sudo apt install build-essential $ sudo apt-get install x11proto-xext-dev $ sudo apt-get install libx11-dev $ sudo apt-get install l…

C语言回调函数进阶篇:全面总结与实战技巧

在C语言的编程世界中&#xff0c;回调函数是一种极其重要的概念。它提供了一种灵活的方式来编写可扩展和模块化的代码。本文将带你深入理解回调函数的原理&#xff0c;并通过一系列案例&#xff0c;系统且全面地总结回调函数的使用技巧。 一、回调函数解析 1.什么是回调函数&…

实战教程:Python实现高校爬虫,运用协同过滤与k-means算法进行专业评分分析

&#x1f393; 作者&#xff1a;计算机毕设小月哥 | 软件开发专家 &#x1f5a5;️ 简介&#xff1a;8年计算机软件程序开发经验。精通Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等技术栈。 &#x1f6e0;️ 专业服务 &#x1f6e0;️ 需求定制化开发源码提…

【工具】复制网页为markdown的浏览器插件

本文首发于 ❄️慕雪的寒舍 说明 如果您需要转载或者想保存他人的文章。可以使用一个油猴插件&#xff0c;快速将网站页面复制为markdown&#xff08;以下简称md&#xff09;。 只要目标网站是支持md语法&#xff08;大部分博客站点都是支持的&#xff09;那么复制下来的效果…

利用VirtualBox安装CentOS系统

博主这次用VirtualBox虚拟机安装CentOS系统。无论是大小型项目都是要发布到云主机上面&#xff0c;必然要用到Linux系统&#xff0c;有的人的本地电脑硬件配置不高&#xff0c;没有办法运行数据库集群&#xff0c;所以只能借助云主机。毕竟云主机也是Linux系统&#xff0c;大家…