当前位置: 首页 > news >正文

雪花ID

雪花ID

unit core.Snowflake;interfaceusesSysUtils, SyncObjs;const// 最大可用69年MaxYears = 69;// 机器id所占的位数WorkerIdBits = 5;// 数据标识id所占的位数DatacenterIdBits = 5;// 序列在id中占的位数SequenceBits = 12;// 机器ID向左移12位WorkerIdShift = SequenceBits;// 数据标识id向左移17位(12+5)DatacenterIdShift = SequenceBits + WorkerIdBits;// 时间截向左移22位(5+5+12)TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;TicksPerMillisecond = 10000;
{$WARNINGS OFF}// 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)SequenceMask = -1 xor (-1 shl SequenceBits);// 支持的最大机器idMaxWorkerId = -1 xor (-1 shl WorkerIdBits);// 支持的最大数据标识id,结果是 31MaxDatacenterId = -1 xor (-1 shl DatacenterIdBits);
{$WARNINGS ON}typeTWorkerID = 0 .. MaxWorkerId;TDatacenterId = 0 .. MaxDatacenterId;typeTSnowflakeIdWorker = class(TObject)privateFWorkerID: TWorkerID;FDatacenterId: TDatacenterId;FEpoch: Int64;FSequence: Int64;FLastTimeStamp: Int64;FStartTimeStamp: Int64;FUnixTimestamp: Int64;FIsHighResolution: Boolean;/// <summary>/// 阻塞到下一个毫秒,直到获得新的时间戳/// </summary>/// <param name="ATimestamp ">上次生成ID的时间截</param>/// <returns>当前时间戳 </returns>
    function WaitUntilNextTime(ATimestamp: Int64): Int64;/// <summary>/// 返回以毫秒为单位的当前时间/// </summary>/// <remarks>/// 时间的表达格式为当前计算机时间和1970年1月1号0时0分0秒所差的毫秒数/// </remarks>
    function CurrentMilliseconds: Int64;function CurrentTimeStamp: Int64;function ElapsedMilliseconds: Int64;privateclass function GetInstance: TSnowflakeIdWorker;constructor Create;destructor Destroy;protectedfunction GetEpoch: TDateTime;procedure SetEpoch(const Value: TDateTime);public/// <summary>/// 获得下一个ID (该方法是线程安全的)/// </summary>
    function NextId: Int64;/// <summary>/// 工作机器ID(0~31)/// </summary>
    property WorkerID: TWorkerID read FWorkerID write FWorkerID;/// <summary>/// 数据中心ID(0~31)/// </summary>
    property DatacenterId: TDatacenterId read FDatacenterId write FDatacenterId;/// <summary>/// 开始时间/// </summary>
    property Epoch: TDateTime read GetEpoch write SetEpoch;end;varFLock: TCriticalSection;FInstance: TSnowflakeIdWorker = nil;_ServerDateTime: TDateTime;      //服务器时间_ServerTimeStamp: Integer = 0;   //服务器时间跟本地时间间隔,毫秒constERROR_CLOCK_MOVED_BACKWARDS = 'Clock moved backwards. Refusing to generate id for %d milliseconds';ERROR_EPOCH_INVALID         = 'Epoch can not be greater than current';//todo: 电脑时间比正常时间慢n年,出现负数问题
function IdGenerator(): TSnowflakeIdWorker;implementationusesMath,
//  TimeSpan,
  Windows,DateUtils;function IdGenerator: TSnowflakeIdWorker;
beginResult := TSnowflakeIdWorker.GetInstance;
end;{ TSnowflakeIdWorker }constructor TSnowflakeIdWorker.Create;
varFrequency: Int64;
begininherited;FIsHighResolution := QueryPerformanceFrequency(Frequency);FSequence      := 0;FWorkerID      := 1;FDatacenterId  := 1;FLastTimeStamp := -1;FEpoch         := DateTimeToUnix(EncodeDate(2019, 12, 12)) * MSecsPerSec;FUnixTimestamp := DateTimeToUnix(Now) * MSecsPerSec;FStartTimeStamp:= CurrentTimeStamp;FInstance := nil;
end;destructor TSnowflakeIdWorker.Destroy;
beginFreeAndNil(FInstance);
end;class function TSnowflakeIdWorker.GetInstance: TSnowflakeIdWorker;
beginFLock.Enter;tryif FInstance = nil thenFInstance := TSnowflakeIdWorker.Create;Result := FInstance;finallyFLock.Leave;end;
end;function TSnowflakeIdWorker.CurrentTimeStamp: Int64;
beginif FIsHighResolution thenQueryPerformanceCounter(Result)elseResult := GetTickCount * Int64(TicksPerMillisecond);
end;function TSnowflakeIdWorker.ElapsedMilliseconds: Int64;
beginResult := (CurrentTimeStamp - FStartTimeStamp) div TicksPerMillisecond;
end;function TSnowflakeIdWorker.GetEpoch: TDateTime;
beginResult := UnixToDateTime(FEpoch div MSecsPerSec);
end;function TSnowflakeIdWorker.NextId: Int64;
varOffset: Integer;Timestamp: Int64;
beginFLock.Enter;tryTimestamp := CurrentMilliseconds();// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常if (Timestamp < FLastTimeStamp) thenbeginOffset := FLastTimeStamp - Timestamp;if Offset <= 5 thenbegin// 时间偏差大小小于5ms,则等待两倍时间Sleep(Offset shr 1);Timestamp := CurrentMilliseconds();// 还是小于,抛异常并上报if Timestamp < FLastTimeStamp thenraise Exception.CreateFmt(ERROR_CLOCK_MOVED_BACKWARDS, [FLastTimeStamp - Timestamp]);end;end;// 如果是同一时间生成的,则进行毫秒内序列if (FLastTimeStamp = Timestamp) thenbeginFSequence := (FSequence + 1) and SequenceMask;// 毫秒内序列溢出if (FSequence = 0) then// 阻塞到下一个毫秒,获得新的时间戳Timestamp := WaitUntilNextTime(FLastTimeStamp);end// 时间戳改变,毫秒内序列重置elseFSequence := 0;// 上次生成ID的时间截FLastTimeStamp := Timestamp;// 移位并通过或运算拼到一起组成64位的IDResult := ((Timestamp - FEpoch) shl TimestampLeftShift)or (DatacenterId shl DatacenterIdShift)or (WorkerID shl WorkerIdShift)or FSequence;finallyFLock.Leave;end;
end;function TSnowflakeIdWorker.WaitUntilNextTime(ATimestamp: Int64): Int64;
varTimestamp: Int64;
beginTimestamp := CurrentMilliseconds();while Timestamp <= ATimestamp doTimestamp := CurrentMilliseconds();Result := Timestamp;
end;procedure TSnowflakeIdWorker.SetEpoch(const Value: TDateTime);
beginif Value > Now thenraise Exception.Create(ERROR_EPOCH_INVALID);if YearsBetween(Now, Value) <= MaxYears thenFEpoch := DateTimeToUnix(Value) * MSecsPerSec;
end;function TSnowflakeIdWorker.CurrentMilliseconds: Int64;
beginResult := FUnixTimestamp + ElapsedMilliseconds;
end;initializationFLock := TCriticalSection.Create();
finalizationFLock.Free;if Assigned(FInstance) thenFInstance.Free;end.
procedure TSnowService.SnowId(const ARequest: THttpRequest; const AResponse: THttpResponse);
varLRequestData, LResponseData: TData;LSnowFlake: TSnowflakeIdWorker;
beginLRequestData := DataPool.Lock;LResponseData := DataPool.Lock;trytryTRequestFunc.UnMarshal(ARequest, LRequestData);LSnowFlake := IdGenerator;LSnowFlake.WorkerID := LRequestData.I[TConst.WorkerId];LSnowFlake.DatacenterId := LRequestData.I[TConst.DataCenterId];LResponseData.I64['snowflake'] := LSnowFlake.NextId;LResponseData.B[TConst.Success] := True;TResponseFunc.Send(AResponse, LResponseData);excepton E: Exception dobeginLResponseData.B[TConst.Success] := False;LResponseData.S[TConst.Msg] := E.Message;TResponseFunc.Send(AResponse, LResponseData);WriteLog('TSnowService.SnowId()' + E.Message);end;end;finallyDataPool.Unlock(LRequestData);end;
end;

 

http://www.jsqmd.com/news/325212/

相关文章:

  • 2026年杭州割圈绒生产企业选择指南,哪家值得选?
  • F.I.R.E. 计算器:通往财务自由的数字导航仪
  • Linux 多线程编程:互斥锁 (Mutex) —— 给共享资源加上“安全锁” - 详解
  • 聊聊好用的聚氨酯结构胶,这些结构胶品牌商值得关注
  • 极简云端文件格式转换工具:安全高效的在线数据处理助手
  • 数据结构==B-树== - 教程
  • 联友邦精密机械的滑轨成型机好用吗,有哪些品牌优势?
  • 2026年钉钉服务商联系电话推荐:覆盖多区域服务网络
  • 基于SSM的文档管理系统的设计与实现任务书
  • AI事件检测系统:让机器学会“读懂”异常
  • 2026全国不锈钢型材优质厂家盘点+选型指南,采购避坑
  • 计算机毕设java制造业企业专件全生命周期管理系统 基于Java的制造业零部件全生命周期管理系统设计与实现 Java技术驱动的制造业专件生命周期管理平台开发
  • PNG 转 WebP 教程:免费在线实现高效图片优化
  • 基于SSM的文档管理系统的设计与实现开题报告
  • 计算机毕设java制氢领域文献管理系统 基于Java的制氢领域文献管理平台设计与实现 Java环境下制氢领域文献信息管理系统开发
  • 三合一全自动SEO外链生成器|多线程批量发链工具|全平台搜索引擎适配外链软件
  • 基于SprintBoot和Vue的农家乐系统开题报告
  • Go有没有反射的一些框架
  • Firecracker:轻量级虚拟化技术赋能无服务器计算
  • 商业股权设计方案:打造“与人类共存亡”的永续型企业
  • 实用指南:Flutter Android Kotlin 插件编译错误完整解决方案
  • 机器学习算法中,如何正确选择参数模型?
  • 查看android 设备是否支持WEP?
  • AI写论文不愁没思路!这4款AI论文生成神器,为你打开创作大门!
  • 聊聊长沙靠谱的新风系统供应商,口碑好的有哪些
  • 水凝胶摩擦影响热膨胀
  • 深圳地区GEO厂家怎么选,哪家性价比高且口碑好
  • AI写论文有诀窍!4款实用AI论文生成工具,帮你快速产出高质量论文!
  • 共话天津充电桩安装可靠组织,费用怎么算排名
  • Claude Code:Ubuntu设置中转