【Go面试向】defer与time.sleep初探
【Go面试向】defer与time.sleep初探
大家好 我是寸铁👊
总结了一篇defer传参与time.sleep初探的文章✨
喜欢的小伙伴可以点点关注 💝
请大家看下面这段代码,看运行结果会出现什么,为什么?
问题
demo
package mainimport ("log""time"
)func main() {start := time.Now()defer func() {log.Printf("匿名函数时间差: %v", time.Since(start))}()defer log.Printf("时间差: %v", time.Since(start))time.Sleep(3 * time.Second)log.Printf("函数结束")
}
这里不少同学会认为:这题我会,先输出
函数结束,待整个函数结束后,根据defer后进先出的顺序依次打印计算的时间差,由于这里睡眠了3秒,两个时间差应该都是3秒左右。
所以答案为:
函数结束
时间差:3s
匿名函数时间差:3s
看到这里,我想说同学你的思路和想法是好的,一开始我也和你一样,但是这里的答案是错的,那为什么错呢?总得有个原因吧!很明显匿名函数的时间差符合逻辑是对的,那为什么时间差与预期不符合呢?下面我来进行分析。
运行结果

分析
这里的关键点在于为什么时间差为0,也就是说为什么时间差这个defer语句没有被time.sleep 所影响?进一步分析,就是查看start的赋值时机在哪?是在一开始调用defer就赋值,还是说在函数结束后给defer中的start赋值,从而造成结果的不同。
带着这个问题,不妨来debug一下,看一下函数语句的执行顺序。
设置断点
要想看一下start的赋值时机,设置断点在出现start变量前面即可。

设置好断点后,开始进行debug
debug查看
step1
一开始,先初始化start的值

step2
接着,来到第一个defer + 匿名函数,看它有没有进去里面的printf语句给start变量进行赋值,step over 直接跳过了匿名函数的defer语句,也就是说明并没有给匿名函数中的defer语句中的start赋值

step3
之后,进入defer语句中,给time.Since中的start进行赋值。
这里,会发现问题的关键所在,对比
defer+匿名函数一开始调用(非执行)时,不会对里面的变量(参数)start进行赋值。
然而普通的defer + printf则在一开始时就会对里面的变量start赋值,赋值后不会先把time.since的结果计算出来,会在defer调用后,也就是光标移动到下一条语句时调用time.sleep计算时间差,其结果就是0s 左右,此时不会在调用时输出,待整个函数执行完毕退出后,依次按照defer 顺序输出。

step4
进一步来到了time.sleep ,这也说明step3 确实给defer 语句赋值了,并没有跳过,现在开始休眠3 s, 观察3s后会光标会去到哪里?
猜想:
3s后会先输出函数结束,之后函数退出,开始执行defer语句.
结合匿名函数的时间差为3s左右,又因为defer+匿名函数中的start还未赋值,会回到开头的defer+匿名函数进行赋值。

等待3s钟

step5
3s后,来到了输出函数结束的语句。

进一步函数退出,也就是整个函数执行完毕!

step6
又回到了刚才的defer + 匿名函数
果然与step4的猜想一致!

关键点来了!
如下图:这里会进入defer + 匿名函数 , 并给里面的start变量赋值。
注意,这里传参start 还是一开始的start! 只不过time.since(start) 的time 增加(休眠)了3s ,这也很好的解释了为什么defer + 匿名函数 输出的是3s 左右,而defer + printf 语句却是输出0s 左右。

之后匿名函数结束

退出当前的整个函数

最后整个函数结束,输出debug 的结果:
这里加了一些debug 调试的时间,以运行结果为准,见下。

运行结果如下:

探讨
在debug 后,我们来探讨一下为什么会出现这样的情况?为什么结果会有所不同?里面的机制是什么?
defer + 输出语句
传值时机:一开始调用defer 时传入
Go 语言中所有的函数调用都是传值的
虽然 defer 是关键字,但是也继承了这个特性。假设我们想要计算 main 函数运行的时间,可能会写出以下的代码:
package mainimport ("fmt""time"
)func main() {start := time.Now()// 这里误以为:startedAt是在time.Sleep之后才会将参数传递给defer所在语句的函数中defer fmt.Println(time.Since(start))time.Sleep(3 * time.Second)
}
关键点:调用defer关键字会立刻拷贝函数中引用的外部参数
所以 time.Since(start) 的结果不是在 main 函数退出之前计算的,而是在 defer 关键字调用时赋值计算的,最终导致上述代码输出 0s。
defer + 匿名函数
传值时机:main函数结束后,执行defer函数 时传入,传入函数指针
package mainimport ("fmt""time"
)func main() {start := time.Now()// 使用匿名函数,传递的是函数的指针defer func() {fmt.Println(time.Since(start))}()time.Sleep(3 * time.Second)
}
那为什么使用匿名函数就可以输出3s 呢?
关键点:defer 使用匿名函数 , 传递的是函数的指针(函数是一种指针类型),结合刚才的断点分析,不会在一开始调用defer + 匿名函数的时候就直接赋值,而是在后面main函数退出时,再执行defer +匿名函数 时再传入函数的指针,并给start变量赋值。
总结
总而言之:一开始调用defer+输出语句会进行传值,会在调用defer 的时候就直接传递值的拷贝(如刚才的defer+输出语句),从而计算时间差。
调用defer + 匿名函数 传递的是指针类型(如函数、匿名函数), 会在main函数退出时,在执行defer +匿名函数 时再传入函数的指针,并给里面的变量赋值。
归根结底,是传入的类型不同,继而导致传入变量的时机不同,造成输出的结果不同!
扩展
面试官:请你用defer与time.sleep写一个计算函数运行时间的程序
相信看到这里的小伙伴,已经很清楚要写什么代码了!
package mainimport ("fmt""time"
)func main() {start := time.Now()// 使用匿名函数,传递的是函数的指针defer func() {fmt.Println(time.Since(start))}()time.Sleep(3 * time.Second)
}
看到这里的小伙伴,恭喜你又掌握了一个知识点👊
希望大家能取得胜利,坚持就是胜利💪
我是寸铁!我们下期再见💕
相关文章:
【Go面试向】defer与time.sleep初探
【Go面试向】defer与time.sleep初探 大家好 我是寸铁👊 总结了一篇defer传参与time.sleep初探的文章✨ 喜欢的小伙伴可以点点关注 💝 请大家看下面这段代码,看运行结果会出现什么,为什么? 问题 demo package mainim…...
fpga外置flash程序烧录流程
Fpga外置FLASH程序烧录流程: step1: 打开vivado2019.2软件,找到hardware manager选项,进入该功能界面; Step2: 确定连接状态,当JTAG正确连接到板卡的调试插针后,会在状态窗口显示…...
什么是通配监听端口? 什么是通配监听IP?
什么是通配监听端口? 监听端口: 指的是服务器或服务开启的特定TCP或UDP端口号,等待客户端连接或发送数据。TCP/IP协议下每个端口只能由一个服务独占监听,一个服务或应用会指定监听特定的一个或多个端口来接收客户端的连接请求。 例如 Web…...
CentOS 安装 Ruby
1.下载 Ruby3.3 并安装 依次执行 wget https://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.0.tar.gz tar -zxvf ruby-3.3.0.tar.gz cd ruby-3.3.0 ./configure make make install 2.查看版本 ruby -v...
Laya3.0 相机使用
摄像机,是3D场景里边最经常使用的对象了。 官方文档:点击这里学习 1.投影 Projection 透视: 模拟人眼的视觉效果,近大远小。模拟物理世界的规律,将眼睛或相机抽象成一个点,此时视锥体内的物体投影到视平…...
前端语音识别(webkitSpeechRecognition)
前端语音识别(webkitSpeechRecognition)-CSDN博客 Excerpt 文章浏览阅读1.8k次,点赞4次,收藏4次。浏览器实现语音转文字_webkitspeechrecognition webkitSpeechRecognition(语音识别) <span class="token comment">// 创建一个webkitSpeechRecognition实…...
Flutter中状态管理选项的比较:利弊探索
Flutter 应用程序开发的一个关键方面是管理状态,这确保了整个应用程序的数据一致性和更新。然而,Flutter 提供了多种状态管理解决方案,每种解决方案都有自己的优缺点。在这篇博客中,我们将探讨 Flutter 中一些流行的状态管理选项&…...
# [NOI2019] 斗主地 洛谷黑题题解
[NOI2019] 斗主地 题目背景 时限 4 秒 内存 512MB 题目描述 小 S 在和小 F 玩一个叫“斗地主”的游戏。 可怜的小 S 发现自己打牌并打不过小 F,所以他想要在洗牌环节动动手脚。 一副牌一共有 n n n 张牌,从上到下依次标号为 1 ∼ n 1 \sim n 1∼…...
踩坑(6)Redisson调用unlockAsync方法释放锁失败
问题描述 通过redisson的lockAsync异步方法获取到锁之后,再业务执行完成后调用lock.unlockAsync()无法释放当前锁,导致后续的方法被阻塞 public void asyncLock() {RLock lock redissonClient.getLock("asyncLock");RFuture<Void> fut…...
树莓派实战应用:基于人脸识别系统
引言: 随着人工智能技术的不断发展,人脸识别技术已经广泛应用于各种场景,如门禁系统、安全监控等。树莓派作为一种功能强大的迷你计算机,也可以用于搭建人脸识别检测系统。 一、项目简介 人脸识别系统是一种基于人工智能技术的身…...
5G赋能智慧文旅:科技与文化的完美结合,打造无缝旅游体验,重塑旅游业的未来
一、5G技术:智慧文旅的强大引擎 5G技术的起源可以追溯到2010年,当时世界各国开始意识到4G技术已经达到了瓶颈,无法满足日益增长的移动通信需求。2013年,国际电信联盟(ITU)成立了5G技术研究组,开…...
大模型:相关参数总结
文章目录 一、相关参数 一、相关参数 参数名称是否必填默认值描述model是调用的模型名称message是传入模型的消息max_tokens否返回tokens的数量temperature否top_p否n否表示一个问答返回几个回答的结果信息stream否false表示应答的方式,false表示返回全部的结果&am…...
腾讯云短信开发
短信服务应用申请 """ 准备工作 1)创建短信应用 - 应用管理 2)申请短信签名 - 国内短信 > 签名管理 3)申请短信模块 - 国内短信 > 正文模板管理 """python中开发腾讯云短信服务 """ 1…...
Dockerfile:如何写一个Dockerfile文件?
如何写一个Dockerfile文件? 🚨推荐参考:Dockerfile:如何写一个Dockerfile文件? 现在的项目肯定都离不开docker,只要是流水线部署就会涉及Dockerfile文件,那么如何写一个正确的编写一个Dockerfil…...
Lua 中的高级特性:模块的使用、字符串模式匹配、高阶函数和表的元方法
### 1. 模块的使用 在 Lua 中,模块是一种封装代码的方式,使得代码可以被重用。下面是一个简单的模块定义和使用的示例: lua -- 定义一个名为 mymodule 的模块 mymodule {} function mymodule.sayHello() print("Hello from my mo…...
openssl3.2/test/certs - 040 - EC cert with named curve signed by named curve ca
文章目录 openssl3.2/test/certs - 040 - EC cert with named curve signed by named curve ca概述笔记END openssl3.2/test/certs - 040 - EC cert with named curve signed by named curve ca 概述 openssl3.2 - 官方demo学习 - test - certs 笔记 /*! * \file D:\my_dev…...
LabVIEW准分子激光器控制系统
LabVIEW准分子激光器控制系统是为了实现准分子激光光源在工业、医疗和科研领域的应用集成及其功能的扩展。系统由PC端和激光器端两部分构成,通过光隔离的RS232通讯连接,以实现稳定可靠的控制与通信。 系统主要由微控制单元(MCU)主…...
热血江湖服务端服务器架设教程
热血江湖服务端服务器架设教程 大家好,我是艾西今天简单的说下热血江湖架设需要哪些东西然后怎么操作,不管你是自己玩还是对外开放,这对于有兴趣的小伙伴总的都是一件好事。技多不压身就是这么个道理,当你需要用上时还希望能记起…...
美易平台:美元指数微幅回落
在最新的金融市场动态中,美元指数经历了0.5%的下跌,报告显示当前指数为103.03。这一变化对全球经济和货币市场产生了一定的影响。在这样的市场环境下,互联网金融券商如美易makeasy平台如何应对变化,并保持其服务质量和客户资产安全…...
编译和链接---C语言
引言 众所周知,C语言是一门高级的编程语言,是无法被计算机直接读懂的,C语言也不同于汇编PHP,无法直接翻译成机器语言,在学习的过程中,你是否好奇过我们所敲的C语言代码,是如何一步步翻译成机器…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...
中科院1区顶刊|IF14+:多组学MR联合单细胞时空分析,锁定心血管代谢疾病的免疫治疗新靶点
中科院1区顶刊|IF14:多组学MR联合单细胞时空分析,锁定心血管代谢疾病的免疫治疗新靶点 当下,免疫与代谢性疾病的关联研究已成为生命科学领域的前沿热点。随着研究的深入,我们愈发清晰地认识到免疫系统与代谢系统之间存在着极为复…...
