雪花算法(DELPHI实现)
<p>雪花算法(DELPHI实现)</p><p>生成ID能够按照时间有序生成。</p>
<p>分布式系统内不会产生重复id(用workerId来做区分)。</p>
<p>自增ID:对于数据敏感场景不宜使用,且不适合于分布式场景。</p>
<p>GUID:采用无意义字符串,数据量增大时造成访问过慢,且不宜排序。</p>
<p><strong>算法描述:</strong></p>
<ul>
<li>最高位是符号位,始终为0,不可用。</li>
<li>41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。</li>
<li>10位的机器标识,10位的长度最多支持部署1024个节点。</li>
<li>12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。</li>
</ul>
<p><img src="https://img2018.cnblogs.com/blog/368779/201907/368779-20190708095714142-1276562354.png"></p>
<p>在delphi7下面,测试通过。</p>
<p>下面的算法,适用于单机构生成不重复ID。</p>
<p> </p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">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.
</pre>
</div>
<p> 下面的算法,适用于连锁机构生成分布式ID:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">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.
</pre>
</div>
<p> </p>
<p> </p>
<p> </p>
<p> 演示效果:</p>
<p><img src="https://img2018.cnblogs.com/blog/368779/201907/368779-20190706183652513-840464133.png"></p>
</div>
<div id="MySignature" role="contentinfo">
<p>本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/11143681.html</p><br><br>
来源:https://www.cnblogs.com/hnxxcxg/p/11143681.html
頁:
[1]