返回顶部
首页 > 资讯 > 后端开发 > GO >记一次go语言使用time.Duration类型踩过的坑
  • 447
分享到

记一次go语言使用time.Duration类型踩过的坑

2024-04-02 19:04:59 447人浏览 泡泡鱼
摘要

目录01 踩到的坑02 time.Duration的真实面目03 问题解决04 time.Duration编程实践05 总结01 踩到的坑 先来说说在项目中踩到的使用time.Dur

01 踩到的坑

先来说说在项目中踩到的使用time.Duration类型的坑。我们的背景是要做一个延时任务。延时任务就是指将一个任务延迟到一定的时间后再执行,所以就需要根据延时时间计算出该任务要执行的时间。我们这里的延时时间以毫秒为单位,当时我们定义的是500毫秒。即设置了一个全局的变量interval time.Duration。 即interval = 500 * time.Milliseconds。然后就通过以下公式来计算要

执行的时间了:

可执行时间=当前时间+延迟时间可执行时间=当前时间 + 延迟时间可执行时间=当前时间+延迟时间

由以上公式可得到我们的一个任务的可执行时间为 time.Now().UnixMilli() + int64(interval) 。大家看这里有什么问题吗?
问题在于计算的结果值不是在当前的毫秒数上增加了500,而是增加了500000000,多了6个零。这是为什么呢?

02 time.Duration的真实面目

我们从源码中找到答案。我们从time包中看到time.Duration的定义:

// A Duration represents the elapsed time between two instants
// as an int64 nanosecond count. The representation limits the
// largest representable duration to approximately 290 years.
type Duration int64

由源码可知,Duration本质上是一个int64的类型。从注释可知,代表的是两个时间点之间持续的纳秒数 。 所以这里有两点信息 :一是该类型代表的是一段持续时间,二是该类型的基本单位是纳秒。 这里我先重点关注基本单位是纳秒这点。我们再来看几个常量的定义:

const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)

一个单位的Duration是代表1纳秒。 而time.Micorsecond、time.Millisecond、time.Second、time.Minute、time.Hour的单位实际上都是纳秒。也就是说我们使用到的time.Millisecond实际上是1000000纳秒。所以就有了interval=500*time.Millisecond=500 * 1000000 = 500000000,然后在计算延时后的执行时间时两个单位不一样造成计算出来的值不是预期的增加500毫秒的结果。

03 问题解决

知道了time.Duration类型的基本单位是代表纳秒之后,我们就可以很好的解决了。就是统一单位。
我们也发现,在time包中对于time.Duration类型的对象有转换成秒、毫秒等对应的函数。如下:

所以我们直接获取即可:

可执行时间 := time.Now().UnixMilli() + interval.Millisecond()

04 time.Duration编程实践

上面是我在编码时因为没搞懂time.Duration类型的本质含义猜到的一个坑。那么我们在实际编码时在定义和持续时间有关的变量时应该使用int类型还是time.Duration类型呢?
我的建议是大家尽量用time.Duration类型。为什么呢?第一个原因是和标准库类型统一,不用做过多的转换。因为我们观察可以发现,无论是开源程序,还是Go的标准库,凡是和持续时间相关的变量类型都是使用的time.Duration,这样类型统一我们来看几个例子。

示例一:context.WithTimeout

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
    return WithDeadline(parent, time.Now().Add(timeout))
}

我们看到,context包中的WithTimeout函数中的timeout的类型是time.Duration。

示例二:time.Sleep

func Sleep(d Duration)

time包中的Sleep函数的d参数也是Duration类型。

示例三:time.NewTicker

func NewTicker(d Duration) *Ticker

如果我们自己的程序中相关变量使用的也是time.Duration类型,那么在调用标准库函数时就不用进行类型转化了。

第二个原因就是该类型在语义上就明确了time.Duration类型值的基本单位是纳秒。这样在函数调用过程中就不用进行单位换算了。我们看下面以连接Redis的示例是如何进行类型转换的。

我们在连接redis的时候,一般都会设置读写超时时间以及定义redis的地址,我们有如下配置:

type config struct {
    Addr string
    ReadTimeout int64 //以秒为单位
}

我们使用包GitHub.com/go-redis/redis/v8包来连接redis。我们看到

func NewRedisClient(conf config) *redis.Client {
    opt := redis.Options{
        Addr: conf.Addr,
        ReadTimeout: conf.ReadTimeout * time.Second
    }
    
    client := redis.NewClient(opt)
    
    return client
}

我们知道redis.Options中的ReadTimeout的类型是time.Duration。 那么,如果我们在config配置文件中定义的int64类型以秒为单位的话,则在NewRedisClient中给redis.Options中的ReadTimeout赋值时,需要做如下转换:

conf.ReadTimeout * time.Second

那如果我们在config中定义的ReadTimeout的代表的是毫秒的话,那么在NewRedisClient函数中就需要做如下转换:

conf.ReadTimeout * time.Millisecond

那在config结构体中的ReadTimeout所代表的含义是秒还是毫秒还是其他的由谁来保证呢,只能是人为的进行保证。而如果使用time.Duration类型就是由系统类型来保证的,因为go的标准库定义的该类型就是代表纳秒数。

05 总结

本文从在实际编程中遇到的问题出发,了解到time.Duration类型实际代表的是持续的纳秒数。同时又分析了使用time.Duration类型的好处。在项目中,如果遇到和持续时间相关的变量的定义,也建议大家尽量使用time.Duration类型。

到此这篇关于记一次go语言使用time.Duration类型踩过的坑的文章就介绍到这了,更多相关go time.Duration内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: 记一次go语言使用time.Duration类型踩过的坑

本文链接: https://lsjlt.com/news/163898.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 记一次go语言使用time.Duration类型踩过的坑
    目录01 踩到的坑02 time.Duration的真实面目03 问题解决04 time.Duration编程实践05 总结01 踩到的坑 先来说说在项目中踩到的使用time.Dur...
    99+
    2024-04-02
  • go语言使用time.Duration类型的坑有哪些
    这篇文章的内容主要围绕go语言使用time.Duration类型的坑有哪些进行讲述,文章内容清晰易懂,条理清晰,非常适合新手学习,值得大家去阅读。感兴趣的朋友可以跟随小编一起阅读吧。希望大家通过这篇文章有所收获!01 踩到的坑先来说说在项目...
    99+
    2023-06-29
  • 记一次使用nacos2踩到的坑
    前言 本文素材来源朋友学习nacos2.1.1踩到的坑。直接上正菜 坑点一:出现端口被占用 因为是学习使用,朋友就在物理机搭建了搭建了nacos伪集群,即ip都一样,端口分别为8848,8847,88...
    99+
    2023-09-17
    nginx 服务器 运维 springcloud
  • 记一次MySQL更新语句update的踩坑
    背景 最近在一次线上作业过程中执行了一句DML语句,本以为万无一失,结果应用反馈说没有更新,数据还是没有变,最后经过排查才发现是我语句写错了,导致update语句执行的结果与预期不符。 情景再现 为了方便演示,建立一...
    99+
    2022-05-28
    MySQL 更新语句 MySQL update
  • 记一次数据库迁移的踩坑过程
    迁移步骤 迁移数据库是一项需要很谨慎的任务。整个迁移过程大概分成以下几步: 备份原数据库数据 //备份数据库,并指定日期 mysqldump -uadmin -p****** databaseName | gzip > /databak...
    99+
    2018-05-03
    记一次数据库迁移的踩坑过程
  • Go使用proto3的踩坑实战记录
    开发环境:windows10,golang1.18.2,goland2022.2 最近在写项目时,一些数据类的结构以protobuf文件给定。因此,需要将这些protobuf文件转换...
    99+
    2023-02-13
    go proto3 go使用proto3
  • 踩过的坑:Go语言项目开发经验分享
    踩过的坑:Go语言项目开发经验分享近年来,Go语言作为一门开发效率高、性能优异的编程语言,受到了越来越多开发者的关注和喜爱。然而,虽然Go语言有着简洁的语法和强大的并发能力,但在实际项目开发中,我们也会踩上一些坑。在本文中,我将分享一些我在...
    99+
    2023-11-04
    Go语言 经验分享 项目开发
  • 踩过的坑:Go语言项目开发经验与教训
    踩过的坑:Go语言项目开发经验与教训在软件开发的道路上,每个开发者都会不可避免地踩过一些坑。当然,对于Go语言的开发者来说也不例外。本文将分享我在使用Go语言进行项目开发过程中所踩过的坑,希望能给其他开发者带来一些经验和教训。不同版本的Go...
    99+
    2023-11-03
    经验 Go语言 项目开发
  • Go语言日志内聚复用及gjson踩坑记录分享
    目录统一日志格式打印日志封装打印日志的方法内聚和复用gjson今天分享一下最近遇到的坑: 以下代码示例使用GoFrame框架,下文简称为gf框架。 统一日志格式 我有个不好的习惯,不...
    99+
    2024-04-02
  • go语言类型断言怎么使用
    本篇内容主要讲解“go语言类型断言怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“go语言类型断言怎么使用”吧!在go语言中,类型断言是一个使用在接口值上的操作,用于检查接口类型变量所持有...
    99+
    2023-07-05
  • 记录一次一路踩坑的Android Studio平台c++项目配置及编译过程
    //TODO:点太多,简要记录,有时间在整理(NEVERDO) 使用cmake jni资料:https://www.jianshu.com/p/87ce6f565d37 坑总结...
    99+
    2022-06-06
    Android Studio c+ studio C++ Android
  • Go语言中interface类型怎么使用
    今天小编给大家分享一下Go语言中interface类型怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Go语言中int...
    99+
    2023-07-06
  • Go语言中的映射类型如何使用?
    Go语言中的映射类型如何使用? 在Go语言中,映射(map)是一种内置的数据结构,用于存储键值对。映射允许通过键来快速检索值,类似于其他语言中的字典或哈希表。在本文中,我们将介绍Go语...
    99+
    2024-04-02
  • 一文带你了解Go语言中的类型断言和类型转换
    目录类型断言类型判断为什么需要断言类型转换什么时候使用类型转换类型为什么称为转换类型结论在Go中,类型断言和类型转换是一个令人困惑的事情,他们似乎都在做同样的事情。 下面是一个类型断...
    99+
    2024-04-02
  • 总结一下关于在Java8中使用stream流踩过的一些坑
    Java8的stream流 第一个坑: Collectors.toAsList()其实是new了一个list,在向里面赋值。 注意这里Collectors.toList()的写法,...
    99+
    2024-04-02
  • 使用Go语言编写什么类型的程序?
    go 语言可用于编写各种类型的应用程序,例如网络应用程序(web 服务器、api、微服务)、命令行工具(系统管理脚本、数据处理程序、测试工具)和并发应用程序(分布式系统、消息队列、数据流...
    99+
    2024-04-03
    go语言 程序开发
  • Go语言中引用类型的概述
    Go语言中引用类型的概述 Go语言是一种由谷歌开发的开源编程语言,其设计目标之一是简洁、高效且易于使用。在Go语言中,引用类型是一种特殊的数据类型,它们在内存中存储的是数据的引用而不是...
    99+
    2024-02-22
    go语言 概述 引用类型 string类 键值对
  • 如何使用GO语言存储数据类型?
    GO语言是一种非常流行的开发语言,它的速度非常快,可以用于开发高性能应用程序。但是,GO语言的强大并不仅限于速度,它还有很多其他的特性,比如存储数据类型。在本文中,我们将介绍如何使用GO语言存储不同类型的数据,并提供一些实际的演示代码。 一...
    99+
    2023-11-12
    数据类型 存储 javascript
  • 如何使用 GO 语言的数据类型来处理自然语言?
    GO 语言是一种开源的编程语言,它具有高效性、可靠性、可扩展性等优点,目前在互联网领域得到了广泛的应用。在自然语言处理方面,GO 语言提供了丰富的数据类型和操作方法,可以帮助开发者轻松地处理文本数据。本文将介绍如何使用 GO 语言的数据类型...
    99+
    2023-10-30
    数据类型 自然语言处理 load
  • Go语言中哪些数据类型是引用类型的?
    在Go语言中,数据类型可以分为值类型和引用类型。值类型直接存储数据的值,而引用类型存储的是数据的内存地址。在Go语言中,以下数据类型属于引用类型: 切片(Slice):切片是一种动态数...
    99+
    2024-02-25
    数据类型 go语言 引用类型 键值对
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作