雪花算法(DELPHI實現)


雪花算法(DELPHI實現)

生成ID能夠按照時間有序生成。

分布式系統內不會產生重復id(用workerId來做區分)。

自增ID:對於數據敏感場景不宜使用,且不適合於分布式場景。

GUID:采用無意義字符串,數據量增大時造成訪問過慢,且不宜排序。

算法描述:

  • 最高位是符號位,始終為0,不可用。
  • 41位的時間序列,精確到毫秒級,41位的長度可以使用69年。時間位還有一個很重要的作用是可以根據時間進行排序。
  • 10位的機器標識,10位的長度最多支持部署1024個節點。
  • 12位的計數序列號,序列號即一系列的自增id,可以支持同一節點同一毫秒生成多個ID序號,12位的計數序列號支持每個節點每毫秒產生4096個ID序號。

在delphi7下面,測試通過。

下面的算法,適用於單機構生成不重復ID。

 

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:

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.

  

 

 

  演示效果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM