Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yhnbgfd/83fc1a48cbcaa9d37b9fe4e13b62c4e0 to your computer and use it in GitHub Desktop.
Save yhnbgfd/83fc1a48cbcaa9d37b9fe4e13b62c4e0 to your computer and use it in GitHub Desktop.
TwitterSnowflake.cs
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