RAD Studio 10.2.3 测试√
unit uAlgorithm; interface uses Winapi.Windows, System.DateUtils, System.SysUtils; type // 算法 TAlgorithm = class end; // 雪花算法 { 雪花算法简单描述: + 最高位是符号位,始终为0,不可用。 + 41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。 + 10位的机器标识,10位的长度最多支持部署1024个节点。 + 12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。 } TSnowflakeAlgorithm = class(TAlgorithm) private FCS: TRTLCriticalSection; // 临界区 FNowTime: Int64; // 现在时间[单位: ms] FLastTime: Int64; // 上个时间[单位: ms] FMachineID: Integer; // 机器标识 0 .. 1023 [十进制 1023 = 二进制 1111111111 ] FCount: Integer; // 计数序列号 0 .. 4095 [十进制 4095 = 二进制 111111111111 ] public constructor Create; destructor Destroy; override; function GetSnowflakeID: Int64; // 获取雪花ID end; var G_SnowflakeAlgorithm: TSnowflakeAlgorithm; implementation { TSnowflakeAlgorithm } constructor TSnowflakeAlgorithm.Create; begin InitializeCriticalSection(FCS); // 初始化临界区 FMachineID := 999; // 固定的机器 ID FLastTime := MilliSecondsBetween(Now, EncodeDateTime(1970, 1, 1, 8, 0, 0, 0)); FCount := 0; end; destructor TSnowflakeAlgorithm.Destroy; begin DeleteCriticalSection(FCS); // 删除临界区 inherited; end; function TSnowflakeAlgorithm.GetSnowflakeID: Int64; begin EnterCriticalSection(FCS); try FNowTime := MilliSecondsBetween(Now, EncodeDateTime(1970, 1, 1, 8, 0, 0, 0)); // 当前毫秒时间戳 if FLastTime = FNowTime then // 如果上一毫秒的时间 = 现在的时间 begin if FCount > 4095 then // 如果同一毫秒内生成的 ID 个数 > 4096 begin // Sleep(1); // 等待下一毫秒再进行生成 while FLastTime >= FNowTime do begin FNowTime := MilliSecondsBetween(Now, EncodeDateTime(1970, 1, 1, 8, 0, 0, 0)); end; FLastTime := FNowTime; // 重新给上一毫秒时间 赋值 end; end else begin FCount := 0; // 初始化计数 FLastTime := FNowTime; // 重新给上一毫秒时间 赋值 end; Result := (FNowTime shl 22) or (FMachineID shl 12) or FCount; Inc(FCount); // 对计数变量进行自增 finally LeaveCriticalSection(FCS); end; end; end.
procedure TForm1.Button_SnowflakeIDClick(Sender: TObject); var i: Integer; begin // 时间是从1970年1月1日8点到当前的间隔[单位: ms] Memo1.Lines.Add('当前时间戳: ' + IntToStr(MilliSecondsBetween(Now, EncodeDateTime(1970, 1, 1, 8, 0, 0, 0)))); G_SnowflakeAlgorithm := TSnowflakeAlgorithm.Create; for i := 0 to 100 do begin Memo1.Lines.Add((G_SnowflakeAlgorithm.GetSnowflakeID).ToString); end; G_SnowflakeAlgorithm.Free; end;
一点点笔记,以便以后翻阅。