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;
运行结果
一点点笔记,以便以后翻阅。