Created
May 4, 2018 09:33
-
-
Save yhnbgfd/83fc1a48cbcaa9d37b9fe4e13b62c4e0 to your computer and use it in GitHub Desktop.
TwitterSnowflake.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace HQMS.Infrastructure.Helpers | |
{ | |
public class TwitterSnowflake | |
{ | |
/// <summary> | |
/// 基准时间 | |
/// </summary> | |
private const long Twepoch = 1288834974657L; | |
/// <summary> | |
/// 机器标识位数 | |
/// </summary> | |
private const int WorkerIdBits = 5; | |
/// <summary> | |
/// 数据标志位数 | |
/// </summary> | |
private const int DatacenterIdBits = 5; | |
/// <summary> | |
/// 序列号识位数 | |
/// </summary> | |
private const int SequenceBits = 12; | |
/// <summary> | |
/// 机器ID最大值 | |
/// </summary> | |
private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits); | |
/// <summary> | |
/// 数据标志ID最大值 | |
/// </summary> | |
private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits); | |
/// <summary> | |
/// 序列号ID最大值 | |
/// </summary> | |
private const long SequenceMask = -1L ^ (-1L << SequenceBits); | |
/// <summary> | |
/// 机器ID偏左移12位 | |
/// </summary> | |
private const int WorkerIdShift = SequenceBits; | |
/// <summary> | |
/// 数据ID偏左移17位 | |
/// </summary> | |
private const int DatacenterIdShift = SequenceBits + WorkerIdBits; | |
/// <summary> | |
/// 时间毫秒左移22位 | |
/// </summary> | |
private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits; | |
private readonly object _locker = new object(); | |
/// <summary> | |
/// 机器ID | |
/// </summary> | |
private long _workerId; | |
/// <summary> | |
/// 数据ID | |
/// </summary> | |
private long _datacenterId; | |
/// <summary> | |
/// 当前时间节点下的序号 | |
/// </summary> | |
private long _sequence; | |
/// <summary> | |
/// 最后一个ID生成的时候的时间 | |
/// </summary> | |
private long _lastTimestamp = -1L; | |
/// <summary> | |
/// Twitter-Snowflake | |
/// </summary> | |
/// <param name="workerId"></param> | |
/// <param name="datacenterId"></param> | |
/// <param name="sequence"></param> | |
public TwitterSnowflake(long workerId = 0L, long datacenterId = 0L, long sequence = 0L) | |
{ | |
if (workerId > MaxWorkerId || workerId < 0) | |
{ | |
throw new ArgumentException($"Worker Id 必须大于等于0,且不能大于MaxWorkerId:{MaxWorkerId}"); | |
} | |
if (datacenterId > MaxDatacenterId || datacenterId < 0) | |
{ | |
throw new ArgumentException($"Datacenter Id 必须大于等于0,且不能大于MaxWorkerId:{MaxDatacenterId}"); | |
} | |
if (sequence > SequenceMask || sequence < 0) | |
{ | |
throw new ArgumentException($"Sequence 必须大于等于0,且不能大于SequenceMask:{SequenceMask}"); | |
} | |
_workerId = workerId; | |
_datacenterId = datacenterId; | |
_sequence = sequence; | |
} | |
/// <summary> | |
/// 获取下一个ID | |
/// </summary> | |
/// <returns></returns> | |
public long Next() | |
{ | |
lock (_locker) | |
{ | |
var timestamp = GetCurrentTimeMillis(); | |
if (timestamp == _lastTimestamp) | |
{ | |
_sequence = (_sequence + 1) & SequenceMask; | |
if (_sequence == 0) | |
{ | |
timestamp = TilNextMillis(_lastTimestamp); | |
} | |
} | |
else | |
{ | |
_sequence = 0; | |
} | |
_lastTimestamp = timestamp; | |
return ((timestamp - Twepoch) << TimestampLeftShift) | (_datacenterId << DatacenterIdShift) | (_workerId << WorkerIdShift) | _sequence; | |
} | |
} | |
/// <summary> | |
/// 防止产生的时间比之前的时间还要小(由于NTP回拨等问题),保持增量的趋势. | |
/// </summary> | |
/// <param name="lastTimestamp"></param> | |
/// <returns></returns> | |
private long TilNextMillis(long lastTimestamp) | |
{ | |
var timestamp = GetCurrentTimeMillis(); | |
while (timestamp <= lastTimestamp) | |
{ | |
timestamp = GetCurrentTimeMillis(); | |
} | |
return timestamp; | |
} | |
/// <summary> | |
/// 获取当前毫秒级时间戳 | |
/// </summary> | |
/// <returns></returns> | |
private long GetCurrentTimeMillis() | |
{ | |
return (long)(DateTime.UtcNow - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalMilliseconds; | |
} | |
/// <summary> | |
/// 将时间转换成该时间下生成的第一个ID,用于跟TwitterSnowflake进行时间相关的比较 | |
/// </summary> | |
/// <param name="time"></param> | |
/// <returns></returns> | |
public long DateTimeToTwitterSnowflake(DateTime time) | |
{ | |
var timestamp = (long)(time.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalMilliseconds; | |
return ((timestamp - Twepoch) << TimestampLeftShift) | (0 << DatacenterIdShift) | (0 << WorkerIdShift) | 0; | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment