golang 中的定时器(timer),更巧妙的处理timeout

今天看到kite项目中的一段代码,发现挺有意思的。

// generateToken returns a JWT token string. Please see the URL for details:
// http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1
func generateToken(aud, username, issuer, privateKey string) (string, error) {
    tokenCacheMu.Lock()
    defer tokenCacheMu.Unlock()

    uniqKey := aud + username + issuer // neglect privateKey, its always the same
    signed, ok := tokenCache[uniqKey]
    if ok {
        return signed, nil
    }

    tknID, err := uuid.NewV4()
    if err != nil {
        return "", errors.New("Server error: Cannot generate a token")
    }

    // Identifies the expiration time after which the JWT MUST NOT be accepted
    // for processing.
    ttl := TokenTTL

    // Implementers MAY provide for some small leeway, usually no more than
    // a few minutes, to account for clock skew.
    leeway := TokenLeeway

    tkn := jwt.New(jwt.GetSigningMethod("RS256"))
    tkn.Claims["iss"] = issuer                                       // Issuer
    tkn.Claims["sub"] = username                                     // Subject
    tkn.Claims["aud"] = aud                                          // Audience
    tkn.Claims["exp"] = time.Now().UTC().Add(ttl).Add(leeway).Unix() // Expiration Time
    tkn.Claims["nbf"] = time.Now().UTC().Add(-leeway).Unix()         // Not Before
    tkn.Claims["iat"] = time.Now().UTC().Unix()                      // Issued At
    tkn.Claims["jti"] = tknID.String()                               // JWT ID

    signed, err = tkn.SignedString([]byte(privateKey))
    if err != nil {
        return "", errors.New("Server error: Cannot generate a token")
    }

    // cache our token
    tokenCache[uniqKey] = signed

    // cache invalidation, because we cache the token in tokenCache we need to
    // invalidate it expiration time. This was handled usually within JWT, but
    // now we have to do it manually for our own cache.
    time.AfterFunc(TokenTTL-TokenLeeway, func() {
        tokenCacheMu.Lock()
        defer tokenCacheMu.Unlock()

        delete(tokenCache, uniqKey)
    })

    return signed, nil
}

这里的  time.AfterFunc 来做token的timeout处理,是我之前都不知道的。

我之前的做法,自己启动一个 单独的 goroutine,对所有的token做遍历,判断是否timeout,timout了就进行删除操作。

看到了这段代码,第一个感觉是很妙,第二个是如果用起来,会不会有啥副作用。

翻看源码:https://golang.org/src/time/sleep.go?h=AfterFunc#L116

// AfterFunc waits for the duration to elapse and then calls f
   114    // in its own goroutine. It returns a Timer that can
   115    // be used to cancel the call using its Stop method.
   116    func AfterFunc(d Duration, f func()) *Timer {
   117        t := &Timer{
   118            r: runtimeTimer{
   119                when: when(d),
   120                f:    goFunc,
   121                arg:  f,
   122            },
   123        }
   124        startTimer(&t.r)
   125        return t
   126    }

这里的startTimer 是用了系统自身的timer实现,只不过是golang在这里做了一层兼容各个平台的封装,应该是没有什么副作用啦。

14    // Interface to timers implemented in package runtime.
    15    // Must be in sync with ../runtime/runtime.h:/^struct.Timer$
    16    type runtimeTimer struct {
    17        i      int
    18        when   int64
    19        period int64
    20        f      func(interface{}, uintptr) // NOTE: must not be closure
    21        arg    interface{}
    22        seq    uintptr
    23    }
    24
    25    // when is a helper function for setting the ‘when‘ field of a runtimeTimer.
    26    // It returns what the time will be, in nanoseconds, Duration d in the future.
    27    // If d is negative, it is ignored.  If the returned value would be less than
    28    // zero because of an overflow, MaxInt64 is returned.
    29    func when(d Duration) int64 {
    30        if d <= 0 {
    31            return runtimeNano()
    32        }
    33        t := runtimeNano() + int64(d)
    34        if t < 0 {
    35            t = 1<<63 - 1 // math.MaxInt64
    36        }
    37        return t
    38    }
    39
    40    func startTimer(*runtimeTimer)
    41    func stopTimer(*runtimeTimer) bool

不得不感慨,原生库还是有很多好东东的,需要自己慢慢发觉。

时间: 2024-08-30 02:28:33

golang 中的定时器(timer),更巧妙的处理timeout的相关文章

[ Javascript ] JavaScript中的定时器(Timer) 是如何工作的!

作为入门者来说,了解JavaScript中timer的工作方式是很重要的.通常它们的表现行为并不是那么地直观,而这是因为它们都处在一个单一线程中.让我们先来看一看三个用来创建以及操作timer的函数. var id = setTimeout(fn, delay); - 初始化一个单一的timer,这个timer将会在一定延时后去调用指定的函数.这个函数(setTimeout)将返回一个唯一的ID,我们可以通过这个ID来取消timer. var id = setInterval(fn, delay

Java中的定时器Timer

java.util.Timer是一个实用工具类,该类用来调度一个线程,使它可以在将来某一时刻执行. Java的Timer类可以调度一个任务运行一次,或定期运行. java.util.TimerTask是一个抽象类,它实现了Runnable接口.我们需要扩展该类以便创建自己的TimerTask,这个TimerTask内部使用java Timer类,可以被调度. Timer类是线程安全的,多进程不需要外部同步机制就可以共享同一个Timer对象.Timer类使用java.util.TaskQueue在

java中的定时器——Timer

一.类概述 Timer是一种定时器工具,用来在一个后台线程计划执行指定任务.它可以计划执行一个任务一次或反复多次. TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务. 二.代码实例 import java.util.Timer; import java.util.TimerTask; public class Reminder ...{ Timer timer; public Reminder(int seconds) ...{ timer = new Timer();

qt中定时器Timer的使用

qt中定时器Timer的使用,布布扣,bubuko.com

C#中WebService 的 Timer定时器过段时间后自动停止运行

我用.net做的一个Timer定时器,定时获取短信并给予回复,但大概过了十几个小时以后,Timer定时器会自动停止,再发送短信就不能收到回复,需要在服务器中重新运行定时器才可以,请教各位! 我是在.net framework中的,有一个Global.asax全局应用程序文件,帖代码:public class Global : System.Web.HttpApplication { double iTimerInterval; System.Timers.Timer timer = new Sy

《React-Native系列》18、 RN之定时器Timer

在web开发中,我们通常需要使用定时器功能,使用setTimeout和setInterval函数. 那么在ReactNative中,是否也提供了定时器的功能呢? 答案是肯定的. 我们还是先看看官网怎么说的. 定时器是一个应用中非常重要的部分.React Native实现了和浏览器一致的定时器Timer. 提供的方法如下: setTimeout, clearTimeout setInterval, clearInterval setImmediate, clearImmediate request

Qt中使用定时器(可使用QObject::timerEvent定时执行,QTimer::singleShot可只触发一次)

在Qt中使用定时器有两种方法,一种是使用QObiect类的定时器:一种是使用QTimer类.定时器的精确性依赖于操作系统和硬件,大多数平台支持20ms的精确度 1.QObject类的定时器 QObject是所有Qt对象的基类,它提供了一个基本的定时器.通过QObject::startTimer(),可以把一个一毫秒为单位的时间间隔作为参数来开始定时器,这个函数返回一个唯一的整数定时器的标识符.这个定时器开始就会在每一个时间间隔"触发",直到明确的使用这个定时器的标识符来调用QObjec

游戏中的定时器

写在前面 游戏中处处都有定时器,基本上每个逻辑部分我们都能看到定时器的影子.如果翻看一下以前网上流传的一些MMO的代码,比如mangos的,比如大唐的,比如天龙的,我们都可以看到形形色色的定时器实现. 在以前,很多程序员用起来C++还都是在用C with Object,以前的C++写callback也好异步也好总是感觉哪里不对劲的样子,所以网上流传的那种线上服务器的代码,一般都是往主循环里硬塞定时器逻辑. 定时器在很多能参考到的代码里都是逻辑和底层不做区分的,这样就会导致一些问题.一方面,底层的

Python之路(第四十五篇)线程Event事件、 条件Condition、定时器Timer、线程queue

一.事件Event Event(事件):事件处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True,那么event.wait 方法时便不再阻塞. Event其实就是一个简化版的 Condition.Event没有锁,无法使线程进入同步阻塞状态. Event() set(): 将标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态. clear(): 将标志设为False. wait(time