我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Go语言中延迟执行语句是哪个

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Go语言中延迟执行语句是哪个

这篇“Go语言中延迟执行语句是哪个”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Go语言中延迟执行语句是哪个”文章吧。

在Go语言中,延迟执行语句是defer语句,语法“defer 任意语句”。defer语句会将其后面跟随的语句进行延迟处理,在defer归属的函数即将返回时,将延迟处理的语句按defer的逆序进行执行;也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。

Go 语言中的延迟执行语句(defer语句)

Go语言中存在一种延迟执行的语句,由defer关键字标识。

defer 关键字会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。

格式如下:

defer 任意语句

defer后的语句不会被马上执行,在defer所属的函数即将返回时,函数体中的所有defer语句将会按出现的顺序被逆序执行,即函数体中的最后一个defer语句最先被执行。

package mainimport "fmt"func main(){fmt.Println("start now")defer fmt.Println("这是第一句defer语句")defer fmt.Println("这是第二句defer语句")defer fmt.Println("这是第三句defer语句")fmt.Println("end")}

执行结果如下:

start nowend这是第三句defer语句这是第二句defer语句这是第一句defer语句

由于defer语句是在当前函数即将返回时被调用,所以defer常常被用来释放资源。

多个延迟执行语句的处理顺序

当有多个 defer 行为被注册时,它们会以逆序执行(类似栈,即后进先出),下面的代码是将一系列的数值打印语句按顺序延迟处理,如下所示:

package mainimport (    "fmt")func main() {    fmt.Println("defer begin")    // 将defer放入延迟调用栈    defer fmt.Println(1)    defer fmt.Println(2)    // 最后一个放入, 位于栈顶, 最先调用    defer fmt.Println(3)    fmt.Println("defer end")}

代码输出如下:

defer begindefer end321

结果分析如下:

  • 代码的延迟顺序与最终的执行顺序是反向的。

  • 延迟调用是在 defer 所在函数结束时进行,函数结束可以是正常返回时,也可以是发生宕机时。

使用延迟执行语句在函数退出时释放资源

处理业务或逻辑中涉及成对的操作是一件比较烦琐的事情,比如打开和关闭文件、接收请求和回复请求、加锁和解锁等。在这些操作中,最容易忽略的就是在每个函数退出处正确地释放和关闭资源。

defer 语句正好是在函数退出时执行的语句,所以使用 defer 能非常方便地处理资源释放问题。

1) 使用延迟并发解锁

在下面的例子中会在函数中并发使用 map,为防止竞态问题,使用 sync.Mutex 进行加锁,参见下面代码:

var (    // 一个演示用的映射    valueByKey      = make(map[string]int)    // 保证使用映射时的并发安全的互斥锁    valueByKeyGuard sync.Mutex)// 根据键读取值func readValue(key string) int {    // 对共享资源加锁    valueByKeyGuard.Lock()    // 取值    v := valueByKey[key]    // 对共享资源解锁    valueByKeyGuard.Unlock()    // 返回值    return v}

代码说明如下:

  • 第 3 行,实例化一个 map,键是 string 类型,值为 int。

  • 第 5 行,map 默认不是并发安全的,准备一个 sync.Mutex 互斥量保护 map 的访问。

  • 第 9 行,readValue() 函数给定一个键,从 map 中获得值后返回,该函数会在并发环境中使用,需要保证并发安全。

  • 第 11 行,使用互斥量加锁。

  • 第 13 行,从 map 中获取值。

  • 第 15 行,使用互斥量解锁。

  • 第 17 行,返回获取到的 map 值。

使用 defer 语句对上面的语句进行简化,参考下面的代码。

func readValue(key string) int {    valueByKeyGuard.Lock()       // defer后面的语句不会马上调用, 而是延迟到函数结束时调用    defer valueByKeyGuard.Unlock()    return valueByKey[key]}

上面的代码中第 6~8 行是对前面代码的修改和添加的代码,代码说明如下:

  • 第 6 行在互斥量加锁后,使用 defer 语句添加解锁,该语句不会马上执行,而是等 readValue() 函数返回时才会被执行。

  • 第 8 行,从 map 查询值并返回的过程中,与不使用互斥量的写法一样,对比上面的代码,这种写法更简单。

2) 使用延迟释放文件句柄

文件的操作需要经过打开文件、获取和操作文件资源、关闭资源几个过程,如果在操作完毕后不关闭文件资源,进程将一直无法释放文件资源,在下面的例子中将实现根据文件名获取文件大小的函数,函数中需要打开文件、获取文件大小和关闭文件等操作,由于每一步系统操作都需要进行错误处理,而每一步处理都会造成一次可能的退出,因此就需要在退出时释放资源,而我们需要密切关注在函数退出处正确地释放文件资源,参考下面的代码:

// 根据文件名查询其大小func fileSize(filename string) int64 {    // 根据文件名打开文件, 返回文件句柄和错误    f, err := os.Open(filename)    // 如果打开时发生错误, 返回文件大小为0    if err != nil {        return 0    }    // 取文件状态信息    info, err := f.Stat()       // 如果获取信息时发生错误, 关闭文件并返回文件大小为0    if err != nil {        f.Close()        return 0    }    // 取文件大小    size := info.Size()    // 关闭文件    f.Close()       // 返回文件大小    return size}

代码说明如下:

  • 第 2 行,定义获取文件大小的函数,返回值是 64 位的文件大小值。

  • 第 5 行,使用 os 包提供的函数 Open(),根据给定的文件名打开一个文件,并返回操作文件用的句柄和操作错误。

  • 第 8 行,如果打开的过程中发生错误,如文件没找到、文件被占用等,将返回文件大小为 0。

  • 第 13 行,此时文件句柄 f 可以正常使用,使用 f 的方法 Stat() 来获取文件的信息,获取信息时,可能也会发生错误。

  • 第 16~19 行对错误进行处理,此时文件是正常打开的,为了释放资源,必须要调用 f 的 Close() 方法来关闭文件,否则会发生资源泄露。

  • 第 22 行,获取文件大小。

  • 第 25 行,关闭文件、释放资源。

  • 第 28 行,返回获取到的文件大小。

在上面的例子中,第 25 行是对文件的关闭操作,下面使用 defer 对代码进行简化,代码如下:

func fileSize(filename string) int64 {    f, err := os.Open(filename)    if err != nil {        return 0    }    // 延迟调用Close, 此时Close不会被调用    defer f.Close()    info, err := f.Stat()    if err != nil {        // defer机制触发, 调用Close关闭文件        return 0    }    size := info.Size()    // defer机制触发, 调用Close关闭文件    return size}

代码中加粗部分为对比前面代码而修改的部分,代码说明如下:

  • 第 10 行,在文件正常打开后,使用 defer,将 f.Close() 延迟调用,注意,不能将这一句代码放在第 4 行空行处,一旦文件打开错误,f 将为空,在延迟语句触发时,将触发宕机错误。

  • 第 16 行和第 22 行,defer 后的语句(f.Close())将会在函数返回前被调用,自动释放资源。

以上就是关于“Go语言中延迟执行语句是哪个”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Go语言中延迟执行语句是哪个

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Go语言中延迟执行语句是哪个

这篇“Go语言中延迟执行语句是哪个”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Go语言中延迟执行语句是哪个”文章吧。在Go
2023-07-04

Go语言如何延迟代码执行若干秒

Go语言提供了多种方法来延迟代码执行若干秒,包括:time.Sleep():暂停当前goroutine执行指定时间。time.After():创建一个timer,在指定时间后发送信号。time.NewTimer():创建一个timer,在指定时间后向其channel发送信号。goroutinechannel:创建一个goroutine,并在channel接收信号时执行代码。选择合适的方法取决于具体场景,例如:time.Sleep()用于简单延迟,无需精确计时。time.After()和time.NewTi
Go语言如何延迟代码执行若干秒
2024-04-02

Go语言如何延迟代码执行若干微秒

Go语言中延迟代码执行微秒的方法有:time.Sleep:阻塞调用线程,指定延迟时间。time.After:返回通道,在指定延迟后发送值。time.NewTimer:安排指定延迟后调用函数。Ticker:定期向通道发送值,可实现重复延迟。选择方法取决于是否需要阻塞、精确度和重复性。time.Sleep简单但不可靠,time.After和time.NewTimer更精确,Ticker用于重复延迟。
Go语言如何延迟代码执行若干微秒
2024-04-02

Go语言如何延迟代码执行若干秒和纳秒

本篇文章介绍了在Go语言中延迟代码执行若干秒或纳秒的各种方法。延迟若干秒使用time.Sleep()函数使用time.After()函数使用time.NewTicker()函数使用time.NewTimer()函数延迟若干纳秒使用time.Now().Add()函数使用time.AfterFunc()函数
Go语言如何延迟代码执行若干秒和纳秒
2024-04-02

Go语言如何延迟代码执行直到指定的时间

在Go语言中,可以通过time包的函数延迟代码执行。time.Sleep()可暂停当前协程;time.After()返回一个在指定时间后发送值的channel;time.AfterFunc()在延迟后执行一个指定函数;time.NewTicker()则创建定期发送值的ticker。选择合适的函数取决于应用程序的具体需求。
Go语言如何延迟代码执行直到指定的时间
2024-04-02

C语言如何延迟代码执行若干秒

本文介绍了在C语言中延迟代码执行若干秒的四种方法:sleep()、usleep()、nanosleep()和select()函数。sleep()完全阻塞进程,而usleep()、nanosleep()和select()非阻塞,允许在暂停期间处理其他任务。所选方法取决于所需的精确度和阻塞行为。
C语言如何延迟代码执行若干秒
2024-04-02

C语言如何延迟代码执行若干微秒

本文介绍了在C语言中延迟代码执行若干微秒的四种方法:usleep()函数:休眠指定微秒数。nanosleep()函数:休眠指定纳秒数。clock_nanosleep()函数:类似于nanosleep(),但使用不同的时钟ID。busy-wait循环:通过循环等待的方式实现延迟,精度高但消耗CPU资源。选择合适的方法取决于精度要求、资源消耗、延迟时间和平台兼容性等因素。
C语言如何延迟代码执行若干微秒
2024-04-02

C语言如何延迟代码执行若干秒和纳秒

本文提供了C语言中延迟代码执行的解决方案,包括使用sleep、nanosleep和usleep函数。sleep用于延迟秒级,nanosleep用于延迟纳秒级,usleep用于延迟微秒级。选择合适的函数取决于所需的精度、可移植性和阻塞性。需要注意的是,实际延迟时间可能与指定时间略有不同,并且精确的延迟通常是不必要的,除非在非常特定的应用中。
C语言如何延迟代码执行若干秒和纳秒
2024-04-02

C语言如何延迟代码执行直到指定的时间

这篇文章介绍了如何在C语言中延迟代码执行,提供了三种方法:sleep()函数用于暂停指定秒数,nanosleep()函数用于以纳秒为单位精确暂停,usleep()函数用于暂停指定微秒数。选择合适的方法取决于所需的精度级别。
C语言如何延迟代码执行直到指定的时间
2024-04-02

C语言switch case语句的执行流程是什么

C语言的switch case语句的执行流程如下:1. 首先,计算switch语句中的表达式的值。2. 根据表达式的值,程序将跳转到与其值相匹配的case分支。3. 如果找到了匹配的case分支,则程序将从该分支开始执行语句,直到遇到bre
2023-09-20

VB.NET中有哪些可执行语句

今天就跟大家聊聊有关VB.NET中有哪些可执行语句,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。VB.NET可执行语句执行一项操作。它调用过程、分支到代码中的另一个位置、循环执行多个
2023-06-17

try、finally与return语句在Java中哪个先执行

今天就跟大家聊聊有关try、finally与return语句在Java中哪个先执行,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Demo1public class Test { p
2023-05-31

php执行哪个语句删除整个数据库

今天小编给大家分享一下php执行哪个语句删除整个数据库的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。首先,我们要知道如何删除
2023-07-05

MyBatis中SQL语句是怎么执行的

MyBatis中的SQL语句执行流程大致如下:配置文件:首先在配置文件(通常是mybatis-config.xml)中配置数据库连接信息、映射文件等。映射文件:在映射文件(通常是mapper.xml)中编写SQL语句、参数映射、结果映射等。
MyBatis中SQL语句是怎么执行的
2024-04-23

GO语言中err接口及defer延迟异常怎么处理

这篇“GO语言中err接口及defer延迟异常怎么处理”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“GO语言中err接口及d
2023-06-30

高效执行 Go 语言中的 POST 请求

在 go 语言中发送 post 请求,可以按照以下步骤进行:导入必要的包。创建一个 http 客户端。创建一个 http 请求,指定方法、url 和请求正文。设置必要的请求标头。执行请求并获取响应。处理响应正文。高效执行 Go 语言中的 P
高效执行 Go 语言中的 POST 请求
2024-04-08

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录