转-- Golang中timer定时器实现原理

一般我们导入import ("time")包,然后调用time.NewTicker(1 * time.Second) 实现一个定时器:

func timer1() {

        timer1 := time.NewTicker(1 * time.Second)

        for {

                select {

                case <-timer1.C:

                        xxx() //执行我们想要的操作

                }

        }

}

再看看timer包中NewTicker的具体实现:

func NewTicker(d Duration) *Ticker {

        if d <= 0 {

                panic(errors.New("non-positive interval for NewTicker"))

        }

        // Give the channel a 1-element time buffer.

        // If the client falls behind while reading, we drop ticks

        // on the floor until the client catches up.

        c := make(chan Time, 1)

        t := &Ticker{

                C: c,

                r: runtimeTimer{

                        when:   when(d),

                        period: int64(d),

                        f:      sendTime,

                        arg:    c,

                },

        }

        startTimer(&t.r)

        return t

}

其中Ticker的具体struct如下:

type Ticker struct {

        C <-chan Time // The channel on which the ticks are delivered.

        r runtimeTimer

}

Ticker中的C为数据类型为Time的单向管道,只能读,不能写

再分下一下runtimeTimer的参数:

r: runtimeTimer{

                        when:   when(d),

                        period: int64(d),

                        f:      sendTime,

                        arg:    c,

                }

其中sendTime为回调函数,startTimer时候注册的,arg为回调函数需要的参数arg

  1. startTimer(&t.r)

再进一步看看startTimer的实现:

func sendTime(c interface{}, seq uintptr) {

        // Non-blocking send of time on c.

        // Used in NewTimer, it cannot block anyway (buffer).

        // Used in NewTicker, dropping sends on the floor is

        // the desired behavior when the reader gets behind,

        // because the sends are periodic.

        select {

        case c.(chan Time) <- Now():

        default:

        }

}

通过往管道里面写时间,注意我们Ticker结构里面的C是单向管道,只能读不能写,那要怎么写数据了

通过类型转化,因为channel是一个原生类型,因此不仅支持被传递,还支持类型转换,装换成双向的管道channel,往里面

写数据,用户API那边提供的是单向管道,用户只能就只能读数据,就相当于一层限制

最后,调用执行具体xxx函数,实现定时执行某些事件的功能:

for {

    select {

        case <-timer1.C:

          xxxx()

     }

   }

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2016-04-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

android应用资源预编译,编译和打包全解析

我们知道,在一个APK文件中,除了有代码文件之外,还有很多资源文件。这些资源文件是通过Android资源打包工具aapt(Android Asset P...

59310
来自专栏Golang语言社区

GO语言并发编程之互斥锁、读写锁详解

在本节,我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都...

2795
来自专栏云瓣

Node.js 异步异闻录

提到 Node.js, 我们脑海就会浮现异步、非阻塞、单线程等关键词,进一步我们还会想到 buffer、模块机制、事件循环、进程、V8、libuv 等知识点。本...

3928
来自专栏noteless

ServletRequest HttpServletRequest 请求方法 获取请求参数 请求转发 请求包含 请求转发与重定向区别 获取请求头字段

实际为   HttpServletRequest  或者  ServletRequest,   两者都为接口

1785
来自专栏跟着阿笨一起玩NET

C#如何控制方法的执行时间,超时则强制退出方法执行

http://www.blue1000.com/bkhtml/c17/2013-01/71047.htm

2792
来自专栏Ken的杂谈

asp.net 解决cookies中文乱码问题

web程序开发中经常需要把信息存入cookies中 ,但是如果将中文写入cookies中会变成乱码

2472
来自专栏小灰灰

Java并发学习之CountDownLatch实现原理及使用姿势

CountDownLatch实现原理及使用姿势 在并发编程的场景中,最常见的一个case是某个任务的执行,需要等到多个线程都执行完毕之后才可以进行,Count...

5.4K10
来自专栏Golang语言社区

GO语言并发编程之互斥锁、读写锁详解

在本节,我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都...

4794
来自专栏Golang语言社区

GO语言并发编程之互斥锁、读写锁详解

在本节,我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都...

38215
来自专栏开发与安全

《Python 源码剖析》一些理解以及勘误笔记(3)

以下是本人阅读此书时理解的一些笔记,包含一些影响文义的笔误修正,当然不一定正确,贴出来一起讨论。 注:此书剖析的源码是2.5版本,在python.org 可...

2870

扫码关注云+社区

领取腾讯云代金券