zoukankan      html  css  js  c++  java
  • 雪花算法(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.
    

      

     

      演示效果:

  • 相关阅读:
    Django模型层之ORM
    bzoj1037 [ZJOI2008]生日聚会
    bzoj4423 [AMPPZ2013]Bytehattan
    bzoj1018 [SHOI2008]堵塞的交通
    关于弦图一些问题的解法
    bzoj1006 [HNOI2008]神奇的国度
    bzoj2561 最小生成树
    bzoj3720 Gty的妹子树
    bzoj3489 A simple rmq problem
    bzoj4066 简单题
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/11143681.html
Copyright © 2011-2022 走看看