如何在Go中将time.Time变量转换为原子类型?

5
在我的RESTFUL网络服务中,这是一个在线游戏,我正在像这样在全局变量中存储每个问题的开始时间:var MyTime time.Time。在每个游戏级别之后,我需要更新它。我的应用程序是分布式的,所以我想确保所有应用程序不同时更新它。这就是为什么我决定将其设置为原子的。
实际上,我熟悉Golang的sync/atomic包。我尝试使用atomic.LoadPointer()方法,但它需要特定的参数类型而且不安全。你有其他方法吗?
更新: 好的,我像这样解决了我的问题。 我将时间变量定义为atomic.Value并使用原子加载和存储方法。这是代码: var myTime atomic.Value myTime.Store(newTime)和加载myTime.Load().(time.Time)
请注意,Load()方法返回接口,因此您应该在末尾写(time.Time)以将其转换为time.Time类型。
3个回答

5

由于time.Time是一个复合类型,因此无法直接完成此操作:

type Time struct {
    // wall and ext encode the wall time seconds, wall time nanoseconds,
    // and optional monotonic clock reading in nanoseconds.
    //
    // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic),
    // a 33-bit seconds field, and a 30-bit wall time nanoseconds field.
    // The nanoseconds field is in the range [0, 999999999].
    // If the hasMonotonic bit is 0, then the 33-bit field must be zero
    // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext.
    // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit
    // unsigned wall seconds since Jan 1 year 1885, and ext holds a
    // signed 64-bit monotonic clock reading, nanoseconds since process start.
    wall uint64
    ext  int64

    // loc specifies the Location that should be used to
    // determine the minute, hour, month, day, and year
    // that correspond to this Time.
    // The nil location means UTC.
    // All UTC times are represented with loc==nil, never loc==&utcLoc.
    loc *Location
}

然而,您可以使用指针来实现这一点,因此如果符合您的需求,则可能会出现* time.Time。但是,通过atomic.LoadPointeratomic.StorePointer使用unsafe包来完成它们的操作的事实,这种做法是不被鼓励的。
如果适用于您的情况,一个更好的方法是使用互斥锁来保护您的值。有许多方法可以做到这一点,但是以下是一个简单的示例:
type MyTime struct {
    t  time.Time
    mu sync.RWMutex
}

func (t *MyTime) Time() time.Time {
    t.mu.RLock()
    defer t.mu.RUnlock()
    return t.t
}

func (t *MyTime) SetTime(tm time.Time) {
    t.mu.Lock()
    defer t.mu.Unlock()
    t.t = tm
}

4

2
如果您只对时间戳感兴趣,那么您可以简单地保留对Unix时间的引用,它是int64类型,并原子性地更新它。
var ts int64

func main() {
    atomic.StoreInt64(&ts, time.Now().Unix())
    t := time.Unix(atomic.LoadInt64(&ts), 0)
    fmt.Println(t)
}

如果您需要整个Time结构体,请继续阅读。

Go 1.19及以上版本

如果您可以接受存储指向time.Time对象的指针,则可以使用atomic.Pointer,这是一个通用结构体,抽象了atomic.LoadPointeratomic.StorePointer。以下是一个简单的示例:

// instantiate generic struct with time.Time
var at = atomic.Pointer[time.Time]{}

func main() {
    t := time.Now()

    at.Store(&t)
    t = *at.Load()

    fmt.Println(t)
}

代码示例:https://go.dev/play/p/KwTMgvJIenx?v=gotip

请注意,在 Go 1.19 中,您也可以使用 atomic.Int64。使用这些原子类型的优势是比顶级函数更加防错;因为值被封装在结构体后面,所以不可能以非原子方式访问该值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接