雪花算法(DELPHI实现)

雪花算法(DELPHI实现)

生成ID能够按照时间有序生成。

分布式系统内不会产生重复id(用workerId来做区分)。

自增ID:对于数据敏感场景不宜使用,且不适合于分布式场景。

GUID:采用无意义字符串,数据量增大时造成访问过慢,且不宜排序。

算法描述:

  • 最高位是符号位,始终为0,不可用。
  • 41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。
  • 10位的机器标识,10位的长度最多支持部署1024个节点。
  • 12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。

在delphi7下面,测试通过。

下面的算法,适用于单机构生成不重复ID。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
unit Snowflake;
 
interface
 
uses
  SysUtils, SyncObjs, DateUtils;
 
type
  TSnowflake = class
  private
    FMachineID: integer;   //机器号
    FLocker: TCriticalSection;
    fTime: Int64;      //时间戳
    fsn: int64;        //序列
  public
    constructor Create;
    destructor Destroy; override;
    property MachineID: Integer read FMachineID write FMachineID;
    function Generate: Int64;
  end;
 
implementation
 
const
  Epoch: int64 = 1539615188000; //北京时间2018-10-15号
  MachineBits: Byte = 10;       //机器号10位  0..1023
  snBits: Byte = 12;          //序列号12位
  timeShift: Byte = 22;     //时间戳左移位数=序列号12位+机器号10位
  machineShift: Byte = 12;   //工作站左移位数
  snMask: Word = 4095;       //12位的计数序列号支持每个节点每毫秒产生4096个ID序号
 
{ TSnowflake }
 
constructor TSnowflake.Create;
begin
  FLocker := TCriticalSection.Create;
end;
 
destructor TSnowflake.Destroy;
begin
  FLocker.Free;
  inherited;
end;
 
function TSnowflake.Generate: Int64;
var
  curtime: Int64;
begin
  FLocker.Acquire;
  try
    curtime := DateTimeToUnix(Now) * 1000;
    if curtime = fTime then
    begin
      fsn := (fsn + 1) and snMask;
      if fsn = 0 then
      begin
        while curtime <= fTime do
          curtime := DateTimeToUnix(Now) * 1000;
      end;
    end
    else
      fsn := 0;
    fTime := curtime;
    Result := (curtime - Epoch) shl timeShift or FMachineID shl machineShift or fsn;
  finally
    FLocker.Release;
  end;
end;
 
initialization
 
end.

 下面的算法,适用于连锁机构生成分布式ID:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
unit Snowflake;
{ 调用演示
procedure TForm1.Button1Click(Sender: TObject);
var s: TSnowflake;
i: Integer;
begin
  s := TSnowflake.Create;
  s.OrgID := 8;
  s.MachineID :=10;
  for i:=1 to 30 do
  begin
    Memo1.Lines.Add(IntToStr(s.Generate));
  end;
  s.Free;
end;
}
interface
 
uses
  SysUtils, SyncObjs, DateUtils;
 
type
  TSnowflake = class
  private
    FOrgID: Integer;      //机构号
    FMachineID: integer;   //机器号
    FLocker: TCriticalSection;
    fTime: Int64;      //时间戳
    fsn: int64;        //序列
  public
    constructor Create;
    destructor Destroy; override;
    property MachineID: Integer read FMachineID write FMachineID;
    property OrgID: Integer read FOrgID write FOrgID;
    function Generate: Int64;
  end;
 
implementation
 
const
  Epoch: int64 = 1539615188000; //北京时间2018-10-15号 curtime := DateTimeToUnix(Now) * 1000;
  OrgBits: Byte = 5;            //机构号   0..31
  MachineBits: Byte = 5;       //机器号    0..31
  snBits: Byte = 12;          //序列号12位
  timeShift: Byte = 22;     //时间戳左移位数=序列号位数+机器号位数+机构号位数
  orgShift: Byte = 17;      //机构号左移位数=序列号位数+机器号位数
  machineShift: Byte = 12;   //工作站左移位数=序列号位数
  snMask: Word = 4095;       //12位的计数序列号支持每个节点每毫秒产生4096个ID序号
 
{ TSnowflake }
 
constructor TSnowflake.Create;
begin
  FLocker := TCriticalSection.Create;
end;
 
destructor TSnowflake.Destroy;
begin
  FLocker.Free;
  inherited;
end;
 
function TSnowflake.Generate: Int64;
var
  curtime: Int64;
begin
  FLocker.Acquire;
  try
    curtime := DateTimeToUnix(Now) * 1000;
    if curtime = fTime then
    begin
      fsn := (fsn + 1) and snMask;
      if fsn = 0 then
      begin
        while curtime <= fTime do
          curtime := DateTimeToUnix(Now) * 1000;
      end;
    end
    else
      fsn := 0;
    fTime := curtime;
    Result := (curtime - Epoch) shl timeShift
      or FOrgID shl orgShift
      or FMachineID shl machineShift
      or fsn;
  finally
    FLocker.Release;
  end;
end;
 
initialization
 
end.

  

 

 

  演示效果:

posted @   delphi中间件  阅读(1973)  评论(1编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~
历史上的今天:
2014-07-06 咏南中间件及中间件集群解决方案
点击右上角即可分享
微信分享提示