Skip to content

Instantly share code, notes, and snippets.

@asyncins
Created July 3, 2020 05:59
Show Gist options
  • Save asyncins/0f3cb506d5475069c83dc8ef2efad081 to your computer and use it in GitHub Desktop.
Save asyncins/0f3cb506d5475069c83dc8ef2efad081 to your computer and use it in GitHub Desktop.
[snowflake-go]
package main
import (
"errors"
"fmt"
"sync"
"time"
)
const (
twepoch = int64(1483228800000) //开始时间截 (2017-01-01)
workeridBits = uint(10) //机器id所占的位数
sequenceBits = uint(12) //序列所占的位数
workeridMax = int64(-1 ^ (-1 << workeridBits)) //支持的最大机器id数量
sequenceMask = int64(-1 ^ (-1 << sequenceBits)) //
workeridShift = sequenceBits //机器id左移位数
timestampShift = sequenceBits + workeridBits //时间戳左移位数
)
// A Snowflake struct holds the basic information needed for a snowflake generator worker
type Snowflake struct {
sync.Mutex
timestamp int64
workerid int64
sequence int64
}
// NewNode returns a new snowflake worker that can be used to generate snowflake IDs
func NewSnowflake(workerid int64) (*Snowflake, error) {
if workerid < 0 || workerid > workeridMax {
return nil, errors.New("workerid must be between 0 and 1023")
}
return &Snowflake{
timestamp: 0,
workerid: workerid,
sequence: 0,
}, nil
}
// Generate creates and returns a unique snowflake ID
func (s *Snowflake) Generate() int64 {
s.Lock()
now := time.Now().UnixNano() / 1000000
if s.timestamp == now {
s.sequence = (s.sequence + 1) & sequenceMask
if s.sequence == 0 {
for now <= s.timestamp {
now = time.Now().UnixNano() / 1000000
}
}
} else {
s.sequence = 0
}
s.timestamp = now
r := int64((now-twepoch)<<timestampShift | (s.workerid << workeridShift) | (s.sequence))
s.Unlock()
return r
}
func main() {
snow := Snowflake{}
for i := 0; i < 3; i++ {
id := snow.Generate()
fmt.Println(id)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment