当前位置:首页 > 文章列表 > Golang > Go问答 > 定时器在使用timer.Reset()时无法按预期工作

定时器在使用timer.Reset()时无法按预期工作

来源:stackoverflow 2024-03-07 17:51:25 0浏览 收藏

哈喽!今天心血来潮给大家带来了《定时器在使用timer.Reset()时无法按预期工作》,想必大家应该对Golang都不陌生吧,那么阅读本文就都不会很困难,以下内容主要涉及到,若是你正在学习Golang,千万别错过这篇文章~希望能帮助到你!

问题内容

我一直在尝试运行我的第一个“go 例程”示例,当我让它运行时,它不会按照 go 文档中规定的带有 timer.reset() 函数的方式工作。

就我而言,我相信我这样做的方式很好,因为我实际上并不关心 chan 缓冲区中有什么(如果有的话)。这样做的目的是,如果 case _, ok := <-watcher.events: 上发生任何事情,则触发 case <-tmr.c: ,然后一切都会安静至少一秒钟。这样做的原因是 case _, ok := <-watcher.events: 可以间隔一微秒到几十个事件,我只关心它们全部完成并且事情再次稳定下来。

但是我担心按照文档所说的“必须这样做”的方式进行操作是行不通的。如果我知道做得更好,我会说文档是有缺陷的,因为它假设缓冲区中有东西,而实际上可能没有,但我不知道做得足够好,有信心做出这样的决定,所以我希望一些专家出来那里可以启发我。

下面是代码。我没有将其放在演示中,因为我必须进行一些清理(删除对程序其他部分的调用),并且我不确定如何使其对文件系统更改做出反应以显示其工作。 p>

我已经在代码中清楚地标记了哪些替代方案有效,哪些无效。

func (pm *PluginManager) LoadAndWatchPlugins() error {

  // DOING OTHER STUFF HERE

    fmt.Println(`m1`)

    done := make(chan interface{})
    terminated := make(chan interface{})

    go pm.watchDir(done, terminated, nil)
    fmt.Println(`m2.pre-10`)

    time.Sleep(10 * time.Second)

    fmt.Println(`m3-post-10`)

    go pm.cancelWatchDir(done)
    fmt.Println(`m4`)

    <-terminated
    fmt.Println(`m5`)

    os.Exit(0) // Temporary for testing

    return Err
}

func (pm *PluginManager) cancelWatchDir(done chan interface{}) {
    fmt.Println(`t1`)

    time.Sleep(5 * time.Second)
    fmt.Println()
    fmt.Println(`t2`)

    close(done)
}

func (pm *PluginManager) watchDir(done <-chan interface{}, terminated chan interface{}, strings <-chan string) {

  watcher, err := fsnotify.NewWatcher()
    if err != nil {
        Logger("watchDir::"+err.Error(), `plugins`, Error)
    }

    //err = watcher.Add(pm.pluginDir)
    err = watcher.Add(`/srv/plugins/`)
    if err != nil {
        Logger("watchDir::"+err.Error(), `plugins`, Error)
    }

    var tmr = time.NewTimer(time.Second)
    tmr.Stop()

    defer close(terminated)
    defer watcher.Close()
    defer tmr.Stop()
    for {
        select {
        case <-tmr.C:
            fmt.Println(`UPDATE FIRED`)
            tmr.Stop()

        case _, ok := <-watcher.Events:
            if !ok {
                return
            }

            fmt.Println(`Ticker: STOP`)
            /*
             *  START OF ALTERNATIVES
             *
             *  THIS IS BY EXAMPLE AND STATED THAT IT "MUST BE" AT:
             *      https://golang.org/pkg/time/#Timer.Reset
             *
             *  BUT DOESN'T WORK
             */
            if !tmr.Stop() {
                fmt.Println(`Ticker: CHAN DRAIN`)
                <-tmr.C // STOPS HERE AND GOES NO FURTHER
            }
            /*
             *  BUT IF I JUST DO THIS IT WORKS
             */
            tmr.Stop()
            /*
             *  END OF ALTERNATIVES
             */

            fmt.Println(`Ticker: RESET`)
            tmr.Reset(time.Second)

        case <-done:
            fmt.Println(`DONE TRIGGERED`)
            return
        }
    }
}

解决方案


除了 icza said(q.v.)之外,请注意 documentation 说:

例如,假设程序尚未收到来自 t.c 的信息:

if !t.stop() {
        <-t.c
}

这不能与来自计时器通道的其他接收同时完成。

有人可能会说这不是一个很好的例子,因为它假设计时器在您调用 t.stop 时正在运行。但它确实继续提到,如果已经有一些现有的 goroutine 正在或可能正在从 t.c 读取数据,那么这是一个主意。

reset 文档重复了所有这些,并且顺序有点错误,因为 resetstop 之前排序。)

本质上,整个区域有点fraught。没有很好的通用答案,因为从t.stop返回到你的调用期间至少有三种可能的情况:

  • 没有人正在收听该频道,并且频道中现在没有定时器滴答声。如果计时器在调用 t.stop 之前已停止,通常会出现这种情况。如果计时器已经停止,t.stop 始终返回 false。
  • 没有人正在收听该频道,频道中现在有计时器滴答声。当计时器正在运行但 t.stop 无法阻止其触发时,总是会出现这种情况。在这种情况下,t.stop 返回 false。当计时器正在运行但在您调用 t.stop 之前触发时,也会出现这种情况,因此它自行停止,因此 t.stop 无法停止它并返回 false。
  • 其他人正在收听该频道。

在最后一种情况下,您不应该执行任何操作。在第一种情况下,您不应该执行任何操作。在第二种情况下,您可能希望从通道接收以便将其清除。这就是他们的例子的目的。

有人可能会说:

if !t.stop() {
        select {
        case <-t.c:
        default:
        }
}

是一个更好的例子。它执行一次非阻塞尝试,该尝试将消耗计时器滴答(如果存在),如果没有计时器滴答,则不执行任何操作。无论调用 t.stop 时计时器是否实际运行,这都有效。事实上,如果 t.stop 返回 true,它甚至可以工作,尽管在这种情况下,t.stop 停止了计时器,因此计时器从未设法将计时器滴答放入通道中。 (因此,如果通道中存在数据,则它必然是先前清除通道失败所遗留的。如果不存在此类错误,则尝试接收也就不必要了。)

但是,如果其他人(其他一些 goroutine)正在或可能正在读取该通道,那么您根本不应该执行此操作。尽管调用了 stop,但无法知道谁(您或他们)将获得通道中可能存在的任何计时器滴答声。

同时,如果您不再使用计时器,那么在通道中留下一个计时器滴答声(如果有的话)相对无害。当通道本身被垃圾收集时,它也会被垃圾收集。当然,这是否明智取决于您对计时器所做的事情,但在这些情况下,只需调用 t.stop 并忽略其返回值就足够了。

您创建一个计时器并停止它立即:

var tmr = time.newtimer(time.second)
tmr.stop()

这没有任何意义,我认为这只是你的一次“意外”。

但更进一步,在循环内部:

case _, ok := <-watcher.events:

当发生这种情况时,您声称这不起作用:

if !tmr.Stop() {
            fmt.Println(`Ticker: CHAN DRAIN`)
            <-tmr.C // STOPS HERE AND GOES NO FURTHER
        }

Timer.Stop() 文档表明,如果此调用停止计时器,则返回 true;如果计时器已停止(或过期),则返回 false。但是你的计时器在创建后就已经停止了,所以 tmr.stop() 正确返回 false ,所以你进入 if 并尝试从 tmr.c 接收,但由于计时器“长时间”停止,所以什么都不会在其通道上发送,因此这是一个阻塞(永远)操作。

如果您是使用 timer.stop() 显式停止计时器的人,则推荐的用于耗尽其通道的“模式”没有任何意义,并且不适用于第二个 timer.stop()称呼。

理论要掌握,实操不能落!以上关于《定时器在使用timer.Reset()时无法按预期工作》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

版本声明
本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
Mac 上终端与 IDE 中运行 Golang 应用程序的不同Mac 上终端与 IDE 中运行 Golang 应用程序的不同
上一篇
Mac 上终端与 IDE 中运行 Golang 应用程序的不同
设置Oracle主目录的正确步骤
下一篇
设置Oracle主目录的正确步骤
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • SEO标题协启动:AI驱动的智能对话与内容生成平台 - 提升创作效率
    协启动
    SEO摘要协启动(XieQiDong Chatbot)是由深圳协启动传媒有限公司运营的AI智能服务平台,提供多模型支持的对话服务、文档处理和图像生成工具,旨在提升用户内容创作与信息处理效率。平台支持订阅制付费,适合个人及企业用户,满足日常聊天、文案生成、学习辅助等需求。
    2次使用
  • Brev AI:零注册门槛的全功能免费AI音乐创作平台
    Brev AI
    探索Brev AI,一个无需注册即可免费使用的AI音乐创作平台,提供多功能工具如音乐生成、去人声、歌词创作等,适用于内容创作、商业配乐和个人创作,满足您的音乐需求。
    2次使用
  • AI音乐实验室:一站式AI音乐创作平台,助力音乐创作
    AI音乐实验室
    AI音乐实验室(https://www.aimusiclab.cn/)是一款专注于AI音乐创作的平台,提供从作曲到分轨的全流程工具,降低音乐创作门槛。免费与付费结合,适用于音乐爱好者、独立音乐人及内容创作者,助力提升创作效率。
    2次使用
  • SEO标题PixPro:AI驱动网页端图像处理平台,提升效率的终极解决方案
    PixPro
    SEO摘要PixPro是一款专注于网页端AI图像处理的平台,提供高效、多功能的图像处理解决方案。通过AI擦除、扩图、抠图、裁切和压缩等功能,PixPro帮助开发者和企业实现“上传即处理”的智能化升级,适用于电商、社交媒体等高频图像处理场景。了解更多PixPro的核心功能和应用案例,提升您的图像处理效率。
    2次使用
  • EasyMusic.ai:零门槛AI音乐生成平台,专业级输出助力全场景创作
    EasyMusic
    EasyMusic.ai是一款面向全场景音乐创作需求的AI音乐生成平台,提供“零门槛创作 专业级输出”的服务。无论你是内容创作者、音乐人、游戏开发者还是教育工作者,都能通过EasyMusic.ai快速生成高品质音乐,满足短视频、游戏、广告、教育等多元需求。平台支持一键生成与深度定制,积累了超10万创作者,生成超100万首音乐作品,用户满意度达99%。
    3次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码