唯一性ID生成器:
using System; using System.Collections.Generic; using System.Text; namespace Test.Core { /// <summary> /// 唯一性ID生成器 /// </summary> public class SFID { /// <summary> /// 初始基准時間戳,小於當前時間點即可 /// 分布式項目請保持此時間戳一致 /// </summary> private static long _twepoch = 0L; /// <summary> /// 毫秒計數器 /// </summary> private static long sequence = 0L; /// <summary> /// 最大機器ID所占的位數 /// </summary> private static long maxWorkerId = 90; /// <summary> /// 一微秒內可以產生計數,如果達到該值則等到下一微妙在進行生成 /// </summary> private static long sequenceMask = 99; /// <summary> /// 最后一次的時間戳 /// </summary> private static long lastTimestamp = -1L; /// <summary> /// 線程鎖對象 /// </summary> private static object locker = new object(); /// <summary> /// 機器碼 /// </summary> private static long _workerId = 99; /// <summary> /// 機器編號 /// </summary> public static long WorkerID { get { return _workerId; } set { if (value >= 0 && value < maxWorkerId) _workerId = value; else throw new Exception($"機器碼必須在0至{ maxWorkerId}之間"); } } /// <summary> /// 獲取多個集合 /// </summary> /// <param name="totalCount"></param> /// <returns></returns> public static IEnumerable<long> NewID(int totalCount) { for (var i = 0; i < totalCount; i++) { yield return NewID(); } } /// <summary> /// 機器編碼的基數 /// </summary> private static long _workerBasic = 10000000000000L; /// <summary> /// 獲取新的ID /// </summary> /// <returns></returns> public static long NewID() { lock (locker) { //WorkerID = workId; long timestamp = timeGen(); if (lastTimestamp == timestamp) { //同一微妙中生成ID sequence++; //用&運算計算該微秒內產生的計數是否已經到達上限 if (sequence > sequenceMask) { //一微妙內產生的ID計數已達上限,等待下一微妙 timestamp = tillNextMillis(lastTimestamp); } } else { //不同微秒生成ID sequence = 0; //計數清0 } if (timestamp < lastTimestamp) { //如果當前時間戳比上一次生成ID時時間戳還小,拋出異常,因為不能保證現在生成的ID之前沒有生成過 throw new Exception($"Clock moved backwards. Refusing to generate id for {lastTimestamp - timestamp} milliseconds"); } lastTimestamp = timestamp; //把當前時間戳保存為最后生成ID的時間戳 return WorkerID * _workerBasic + lastTimestamp * 100 + sequence; } } ///// <summary> ///// 獲取新的ID ///// </summary> ///// <param name="workId"></param> ///// <returns></returns> //public static long NewID(int workId) //{ // WorkerID = workId; // return NewID(); //} /// <summary> /// 獲取下一微秒時間戳 /// </summary> /// <param name="lastTimestamp"></param> /// <returns></returns> private static long tillNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } sequence = 0; return timestamp; } private static DateTime _date = new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc); /// <summary> /// 當前時間戳 /// </summary> /// <returns></returns> private static long timeGen() { return (long)(DateTime.UtcNow - _date).TotalMilliseconds; } } }
調用:
long ID = SFID.NewID();