C# 版本雪花算法(SnowFlake)

void Main()
 {
 	var id = new XID.Info(271103830593110952);
 	id.Dump();
 }

 // You can define other methods, fields, classes and namespaces here


 public static class XID
 {
 private static long workerId = 0; //机器ID
 private static long sequence = 0L;
 private static long lastTimestamp = -1L;


 private static readonly int workerIdBits = 10; //机器码字节数。10个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义)
 private static readonly int sequenceBits = 22 - workerIdBits; //计数器字节数,12个字节用来保存计数码
 private static readonly int sequenceShift = workerIdBits; //机器码数据左移位数,就是后面计数器占用的位数
 private static readonly int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数
 private static readonly long workerIdMax = -1L ^ -1L << workerIdBits; //最大WorkId
 private static readonly long sequenceMax = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
 private static readonly object lockObj = new object();
 private static readonly DateTime start_base_time = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc);


 /// <summary>
 /// 设置机器码
 /// </summary>
 /// <param name="id">机器码</param>
 public static void Initialize(string data)
 {
 	long.TryParse(data, out workerId);
 }
 public static long Nextval
 {
 	get
 	{
 		lock (lockObj)
 		{
 			return nextId();
 		}
 	}
 }

 private static long nextId()
 {
 	if (workerId < 1)
 	{
 		workerId = 1982;
 	}
 	workerId = workerId & workerIdMax;
 	long timestamp = timeGen();
 	if (lastTimestamp == timestamp)
 	{
 		//同一微妙中生成ID
 		var abc = (sequence + 1) & sequenceMax; //用&运算计算该微秒内产生的计数是否已经到达上限
 		if (abc == 0)
 		{
 			//一微妙内产生的ID计数已达上限,等待下一微妙
 			timestamp = tillNextMillis(lastTimestamp);
 		}
 		sequence = abc;
 	}
 	else
 	{
 		//不同微秒生成ID
 		sequence = 0; //计数清0
 	}
 	if (timestamp < lastTimestamp)
 	{
 		//如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
 		throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds",
 			lastTimestamp - timestamp));
 	}
 	lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
 	long nextId = timestamp << timestampLeftShift | sequence << sequenceShift | workerId;
 	return nextId;
 }

 /// <summary>
 /// 获取下一微秒时间戳
 /// </summary>
 /// <param name="lastTimestamp"></param>
 /// <returns></returns>
 private static long tillNextMillis(long lastTimestamp)
 {
 	long timestamp = timeGen();
 	while (timestamp <= lastTimestamp)
 	{
 		timestamp = timeGen();
 	}
 	return timestamp;
 }


 /// <summary>
 /// 生成当前时间戳
 /// </summary>
 /// <returns></returns>
 private static long timeGen()
 {
 	return (long)(DateTime.UtcNow - start_base_time).TotalMilliseconds;
 }
 public class Info
 {
 	public Info(long id)
 	{
 		var size = 64;
 		//size = System.Runtime.InteropServices.Marshal.SizeOf(id) * 8;
 		this.Timestamp = id >> timestampLeftShift;
 		this.CreateTime = start_base_time.AddMilliseconds(this.Timestamp);
 		var timeLen = (size - timestampLeftShift);
 		this.SequenceId = id << timeLen >> timeLen >> sequenceShift;
 		this.WorkerId = id & ((1 << sequenceShift) - 1);
 	}
 	public DateTime CreateTime { get; set; }
 	public long Timestamp { get; set; }
 	public long SequenceId { get; set; }
 	public long WorkerId { get; set; }
 }
 }

posted on 2022-03-14 13:00  urmnur  阅读(552)  评论(0编辑  收藏  举报

导航