| @@ -257,3 +257,10 @@ target/ | |||||
| # macOS | # macOS | ||||
| .DS_Store | .DS_Store | ||||
| D/test/test | |||||
| D/libyitterd.a | |||||
| D/dub.*.json | |||||
| */.dub/* | |||||
| */test/.dub/* | |||||
| C/source/build/* | |||||
| D/test/dub.*.json | |||||
| @@ -1,4 +1,4 @@ | |||||
| cmake_minimum_required(VERSION 3.17) | |||||
| cmake_minimum_required(VERSION 3.13) | |||||
| project(YitIdGen) | project(YitIdGen) | ||||
| set(CMAKE_C_STANDARD 11) | set(CMAKE_C_STANDARD 11) | ||||
| @@ -8,6 +8,7 @@ set(CMAKE_C_STANDARD 11) | |||||
| aux_source_directory(. DIR_SRCS) | aux_source_directory(. DIR_SRCS) | ||||
| add_subdirectory(idgen) | add_subdirectory(idgen) | ||||
| #编译动态库 | #编译动态库 | ||||
| #set(LIB_SRC YitIdHelper.h YitIdHelper.c) | #set(LIB_SRC YitIdHelper.h YitIdHelper.c) | ||||
| #add_library(YitIdGenLib SHARED ${LIB_SRC}) | #add_library(YitIdGenLib SHARED ${LIB_SRC}) | ||||
| @@ -21,7 +22,7 @@ add_subdirectory(idgen) | |||||
| set(LIB_SRC YitIdHelper.h YitIdHelper.c) | set(LIB_SRC YitIdHelper.h YitIdHelper.c) | ||||
| add_library(YitIdHelper ${LIB_SRC}) | add_library(YitIdHelper ${LIB_SRC}) | ||||
| add_executable(YitIdGen main.c) | add_executable(YitIdGen main.c) | ||||
| target_link_libraries(YitIdGen YitIdHelper) | |||||
| target_link_libraries(YitIdGen idgen) | |||||
| target_link_libraries(YitIdGen YitIdHelper pthread) | |||||
| target_link_libraries(YitIdGen idgen pthread) | |||||
| @@ -0,0 +1,32 @@ | |||||
| | |||||
| ## 运行环境 | |||||
| ```sh | |||||
| $ cd test | |||||
| $ dub run --compiler=dmd -a=x86_64 | |||||
| ``` | |||||
| ## 调用示例(D) | |||||
| 第1步,**全局** 初始化(应用程序启动时执行一次): | |||||
| ``` | |||||
| // 创建 IdGeneratorOptions 对象,请在构造函数中输入 WorkerId: | |||||
| IdGeneratorOptions options = new IdGeneratorOptions(1); | |||||
| // options.WorkerIdBitLength = 10; // WorkerIdBitLength 默认值6,支持的 WorkerId 最大值为2^6-1,若 WorkerId 超过64,可设置更大的 WorkerIdBitLength | |||||
| // ...... 其它参数设置参考 IdGeneratorOptions 定义,一般来说,只要再设置 WorkerIdBitLength (决定 WorkerId 的最大值)。 | |||||
| // 保存参数(必须的操作,否则以上设置都不能生效): | |||||
| YitIdHelper.setIdGenerator(options); | |||||
| // 以上初始化过程只需全局一次,且必须在第2步之前设置。 | |||||
| ``` | |||||
| 第2步,生成ID: | |||||
| ``` | |||||
| // 初始化以后,即可在任何需要生成ID的地方,调用以下方法: | |||||
| long newId = YitIdHelper.nextId(); | |||||
| ``` | |||||
| 如果基于DI框架集成,可以参考 YitIdHelper 去管理 IdGenerator 对象,须使用 **单例** 模式。 | |||||
| @@ -0,0 +1,9 @@ | |||||
| { | |||||
| "authors": [ | |||||
| "yitter", | |||||
| "HuntLabs" | |||||
| ], | |||||
| "description": "A minimal D application.", | |||||
| "license": "proprietary", | |||||
| "name": "yitterd" | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.contract.IIdGenerator; | |||||
| interface IIdGenerator { | |||||
| long newLong(); | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.contract.ISnowWorker; | |||||
| interface ISnowWorker { | |||||
| long nextId(); | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.contract.IdGeneratorException; | |||||
| class IdGeneratorException : Exception { | |||||
| // this() { | |||||
| // super(); | |||||
| // } | |||||
| this(string message) { | |||||
| super(message); | |||||
| } | |||||
| // this(Throwable cause) { | |||||
| // super(cause); | |||||
| // } | |||||
| this(string message, Throwable cause) { | |||||
| super(message, cause); | |||||
| } | |||||
| // this(string msgFormat, Object... args) { | |||||
| // super(string.format(msgFormat, args)); | |||||
| // } | |||||
| } | |||||
| @@ -0,0 +1,72 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.contract.IdGeneratorOptions; | |||||
| import std.datetime; | |||||
| /** | |||||
| * 雪花算法使用的参数 | |||||
| * 参数说明,参考 README.md 的 “配置参数” 章节。 | |||||
| */ | |||||
| class IdGeneratorOptions { | |||||
| /** | |||||
| * 雪花计算方法 | |||||
| * (1-漂移算法|2-传统算法),默认1 | |||||
| */ | |||||
| short Method = 1; | |||||
| /** | |||||
| * 基础时间(ms单位) | |||||
| * 不能超过当前系统时间 | |||||
| */ | |||||
| // long BaseTime = 1582136402000L; | |||||
| SysTime BaseTime; | |||||
| /** | |||||
| * 机器码 | |||||
| * 必须由外部设定,最大值 2^WorkerIdBitLength-1 | |||||
| */ | |||||
| short WorkerId = 0; | |||||
| /** | |||||
| * 机器码位长 | |||||
| * 默认值6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过22) | |||||
| */ | |||||
| byte WorkerIdBitLength = 6; | |||||
| /** | |||||
| * 序列数位长 | |||||
| * 默认值6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过22) | |||||
| */ | |||||
| byte SeqBitLength = 6; | |||||
| /** | |||||
| * 最大序列数(含) | |||||
| * 设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1]) | |||||
| */ | |||||
| short MaxSeqNumber = 0; | |||||
| /** | |||||
| * 最小序列数(含) | |||||
| * 默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号是0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位 | |||||
| */ | |||||
| short MinSeqNumber = 5; | |||||
| /** | |||||
| * 最大漂移次数(含) | |||||
| * 默认2000,推荐范围500-10000(与计算能力有关) | |||||
| */ | |||||
| short TopOverCostCount = 2000; | |||||
| this() { | |||||
| BaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2)); | |||||
| } | |||||
| this(short workerId) { | |||||
| WorkerId = workerId; | |||||
| BaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2)); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,52 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.contract.OverCostActionArg; | |||||
| /** | |||||
| * Id生成时回调参数 | |||||
| */ | |||||
| class OverCostActionArg { | |||||
| /** | |||||
| * 事件类型 | |||||
| * 1-开始,2-结束,8-漂移 | |||||
| */ | |||||
| int ActionType = 0; | |||||
| /** | |||||
| * 时间戳 | |||||
| */ | |||||
| long TimeTick = 0; | |||||
| /** | |||||
| * 机器码 | |||||
| */ | |||||
| short WorkerId = 0; | |||||
| /** | |||||
| * | |||||
| */ | |||||
| int OverCostCountInOneTerm = 0; | |||||
| /** | |||||
| * 漂移期间生产ID个数 | |||||
| */ | |||||
| int GenCountInOneTerm = 0; | |||||
| /** | |||||
| * 漂移周期 | |||||
| */ | |||||
| int TermIndex = 0; | |||||
| this(short workerId, long timeTick, int actionType, int overCostCountInOneTerm, | |||||
| int genCountWhenOverCost, int index) { | |||||
| ActionType = actionType; | |||||
| TimeTick = timeTick; | |||||
| WorkerId = workerId; | |||||
| OverCostCountInOneTerm = overCostCountInOneTerm; | |||||
| GenCountInOneTerm = genCountWhenOverCost; | |||||
| TermIndex = index; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| module yitter.contract; | |||||
| public import yitter.contract.IdGeneratorException; | |||||
| public import yitter.contract.IdGeneratorOptions; | |||||
| public import yitter.contract.IIdGenerator; | |||||
| public import yitter.contract.ISnowWorker; | |||||
| public import yitter.contract.OverCostActionArg; | |||||
| @@ -0,0 +1,237 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.core.SnowWorkerM1; | |||||
| import yitter.contract.ISnowWorker; | |||||
| import yitter.contract.IdGeneratorOptions; | |||||
| import yitter.contract.OverCostActionArg; | |||||
| import yitter.contract.IdGeneratorException; | |||||
| import std.datetime; | |||||
| class SnowWorkerM1 : ISnowWorker { | |||||
| /** | |||||
| * 基础时间 | |||||
| */ | |||||
| protected SysTime BaseTime; | |||||
| /** | |||||
| * 机器码 | |||||
| */ | |||||
| protected short WorkerId; | |||||
| /** | |||||
| * 机器码位长 | |||||
| */ | |||||
| protected byte WorkerIdBitLength; | |||||
| /** | |||||
| * 自增序列数位长 | |||||
| */ | |||||
| protected byte SeqBitLength; | |||||
| /** | |||||
| * 最大序列数(含) | |||||
| */ | |||||
| protected int MaxSeqNumber; | |||||
| /** | |||||
| * 最小序列数(含) | |||||
| */ | |||||
| protected short MinSeqNumber; | |||||
| /** | |||||
| * 最大漂移次数 | |||||
| */ | |||||
| protected int TopOverCostCount; | |||||
| protected byte _TimestampShift; | |||||
| // protected __gshared Object _SyncLock; // = new byte[0]; | |||||
| protected short _CurrentSeqNumber; | |||||
| protected long _LastTimeTick = 0; | |||||
| protected long _TurnBackTimeTick = 0; | |||||
| protected byte _TurnBackIndex = 0; | |||||
| protected bool _IsOverCost = false; | |||||
| protected int _OverCostCountInOneTerm = 0; | |||||
| protected int _GenCountInOneTerm = 0; | |||||
| protected int _TermIndex = 0; | |||||
| // shared static this() { | |||||
| // _SyncLock = new Object(); | |||||
| // } | |||||
| this(IdGeneratorOptions options) { | |||||
| BaseTime = options.BaseTime != SysTime.min ? options.BaseTime : SysTime(DateTime(2020, 2, 20, 2, 20, 2)); | |||||
| WorkerIdBitLength = options.WorkerIdBitLength == 0 ? 6 : options.WorkerIdBitLength; | |||||
| WorkerId = options.WorkerId; | |||||
| SeqBitLength = options.SeqBitLength == 0 ? 6 : options.SeqBitLength; | |||||
| MaxSeqNumber = options.MaxSeqNumber <= 0 ? (1 << SeqBitLength) - 1 : options.MaxSeqNumber; | |||||
| MinSeqNumber = options.MinSeqNumber; | |||||
| TopOverCostCount = options.TopOverCostCount == 0 ? 2000 : options.TopOverCostCount; | |||||
| _TimestampShift = cast(byte) (WorkerIdBitLength + SeqBitLength); | |||||
| _CurrentSeqNumber = MinSeqNumber; | |||||
| } | |||||
| private void DoGenIdAction(OverCostActionArg arg) { | |||||
| } | |||||
| private void BeginOverCostAction(long useTimeTick) { | |||||
| } | |||||
| private void EndOverCostAction(long useTimeTick) { | |||||
| if (_TermIndex > 10000) { | |||||
| _TermIndex = 0; | |||||
| } | |||||
| } | |||||
| private void BeginTurnBackAction(long useTimeTick) { | |||||
| } | |||||
| private void EndTurnBackAction(long useTimeTick) { | |||||
| } | |||||
| private long NextOverCostId() { | |||||
| long currentTimeTick = GetCurrentTimeTick(); | |||||
| if (currentTimeTick > _LastTimeTick) { | |||||
| EndOverCostAction(currentTimeTick); | |||||
| _LastTimeTick = currentTimeTick; | |||||
| _CurrentSeqNumber = MinSeqNumber; | |||||
| _IsOverCost = false; | |||||
| _OverCostCountInOneTerm = 0; | |||||
| _GenCountInOneTerm = 0; | |||||
| return CalcId(_LastTimeTick); | |||||
| } | |||||
| if (_OverCostCountInOneTerm >= TopOverCostCount) { | |||||
| EndOverCostAction(currentTimeTick); | |||||
| _LastTimeTick = GetNextTimeTick(); | |||||
| _CurrentSeqNumber = MinSeqNumber; | |||||
| _IsOverCost = false; | |||||
| _OverCostCountInOneTerm = 0; | |||||
| _GenCountInOneTerm = 0; | |||||
| return CalcId(_LastTimeTick); | |||||
| } | |||||
| if (_CurrentSeqNumber > MaxSeqNumber) { | |||||
| _LastTimeTick++; | |||||
| _CurrentSeqNumber = MinSeqNumber; | |||||
| _IsOverCost = true; | |||||
| _OverCostCountInOneTerm++; | |||||
| _GenCountInOneTerm++; | |||||
| return CalcId(_LastTimeTick); | |||||
| } | |||||
| _GenCountInOneTerm++; | |||||
| return CalcId(_LastTimeTick); | |||||
| } | |||||
| private long NextNormalId() { | |||||
| long currentTimeTick = GetCurrentTimeTick(); | |||||
| if (currentTimeTick < _LastTimeTick) { | |||||
| if (_TurnBackTimeTick < 1) { | |||||
| _TurnBackTimeTick = _LastTimeTick - 1; | |||||
| _TurnBackIndex++; | |||||
| // 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序 | |||||
| // 最多4次回拨(防止回拨重叠) | |||||
| if (_TurnBackIndex > 4) { | |||||
| _TurnBackIndex = 1; | |||||
| } | |||||
| BeginTurnBackAction(_TurnBackTimeTick); | |||||
| } | |||||
| // try { | |||||
| // Thread.sleep(1); | |||||
| // } catch (InterruptedException e) { | |||||
| // e.printStackTrace(); | |||||
| // } | |||||
| return CalcTurnBackId(_TurnBackTimeTick); | |||||
| } | |||||
| // 时间追平时,_TurnBackTimeTick清零 | |||||
| if (_TurnBackTimeTick > 0) { | |||||
| EndTurnBackAction(_TurnBackTimeTick); | |||||
| _TurnBackTimeTick = 0; | |||||
| } | |||||
| if (currentTimeTick > _LastTimeTick) { | |||||
| _LastTimeTick = currentTimeTick; | |||||
| _CurrentSeqNumber = MinSeqNumber; | |||||
| return CalcId(_LastTimeTick); | |||||
| } | |||||
| if (_CurrentSeqNumber > MaxSeqNumber) { | |||||
| BeginOverCostAction(currentTimeTick); | |||||
| _TermIndex++; | |||||
| _LastTimeTick++; | |||||
| _CurrentSeqNumber = MinSeqNumber; | |||||
| _IsOverCost = true; | |||||
| _OverCostCountInOneTerm = 1; | |||||
| _GenCountInOneTerm = 1; | |||||
| return CalcId(_LastTimeTick); | |||||
| } | |||||
| return CalcId(_LastTimeTick); | |||||
| } | |||||
| private long CalcId(long useTimeTick) { | |||||
| long result = ((useTimeTick << _TimestampShift) + | |||||
| (cast(long) WorkerId << SeqBitLength) + | |||||
| cast(int) _CurrentSeqNumber); | |||||
| _CurrentSeqNumber++; | |||||
| return result; | |||||
| } | |||||
| private long CalcTurnBackId(long useTimeTick) { | |||||
| long result = ((useTimeTick << _TimestampShift) + | |||||
| (cast(long) WorkerId << SeqBitLength) + _TurnBackIndex); | |||||
| _TurnBackTimeTick--; | |||||
| return result; | |||||
| } | |||||
| protected long GetCurrentTimeTick() { | |||||
| SysTime now = Clock.currTime; | |||||
| Duration dur = Clock.currTime - BaseTime; | |||||
| return dur.total!("msecs"); | |||||
| } | |||||
| protected long GetNextTimeTick() { | |||||
| long tempTimeTicker = GetCurrentTimeTick(); | |||||
| while (tempTimeTicker <= _LastTimeTick) { | |||||
| tempTimeTicker = GetCurrentTimeTick(); | |||||
| } | |||||
| return tempTimeTicker; | |||||
| } | |||||
| override | |||||
| long nextId() { | |||||
| synchronized { | |||||
| return _IsOverCost ? NextOverCostId() : NextNormalId(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,50 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.core.SnowWorkerM2; | |||||
| import yitter.core.SnowWorkerM1; | |||||
| import yitter.contract.IdGeneratorOptions; | |||||
| import yitter.contract.IdGeneratorException; | |||||
| import std.format; | |||||
| /** | |||||
| * | |||||
| */ | |||||
| class SnowWorkerM2 : SnowWorkerM1 { | |||||
| this(IdGeneratorOptions options) { | |||||
| super(options); | |||||
| } | |||||
| override | |||||
| long nextId() { | |||||
| synchronized { | |||||
| long currentTimeTick = GetCurrentTimeTick(); | |||||
| if (_LastTimeTick == currentTimeTick) { | |||||
| if (_CurrentSeqNumber++ > MaxSeqNumber) { | |||||
| _CurrentSeqNumber = MinSeqNumber; | |||||
| currentTimeTick = GetNextTimeTick(); | |||||
| } | |||||
| } else { | |||||
| _CurrentSeqNumber = MinSeqNumber; | |||||
| } | |||||
| if (currentTimeTick < _LastTimeTick) { | |||||
| string msg = format("Time error for %d milliseconds", _LastTimeTick - currentTimeTick); | |||||
| throw new IdGeneratorException(msg); | |||||
| } | |||||
| _LastTimeTick = currentTimeTick; | |||||
| long result = ((currentTimeTick << _TimestampShift) + (cast(long) WorkerId << SeqBitLength) + cast(int) _CurrentSeqNumber); | |||||
| return result; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,98 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.idgen.DefaultIdGenerator; | |||||
| import yitter.contract.IIdGenerator; | |||||
| import yitter.contract.ISnowWorker; | |||||
| import yitter.contract.IdGeneratorException; | |||||
| import yitter.contract.IdGeneratorOptions; | |||||
| import yitter.core.SnowWorkerM1; | |||||
| import yitter.core.SnowWorkerM2; | |||||
| import core.thread; | |||||
| import core.time; | |||||
| import std.conv; | |||||
| import std.datetime; | |||||
| import std.stdio; | |||||
| /** | |||||
| * | |||||
| */ | |||||
| class DefaultIdGenerator : IIdGenerator { | |||||
| private __gshared ISnowWorker _SnowWorker = null; | |||||
| this(IdGeneratorOptions options) { | |||||
| if (options is null) { | |||||
| throw new IdGeneratorException("options error."); | |||||
| } | |||||
| // 1.BaseTime | |||||
| SysTime MinBaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2)).add!"years"(-50); | |||||
| if (options.BaseTime < MinBaseTime || options.BaseTime > Clock.currTime) { | |||||
| throw new IdGeneratorException("BaseTime error."); | |||||
| } | |||||
| // 2.WorkerIdBitLength | |||||
| if (options.WorkerIdBitLength <= 0) { | |||||
| throw new IdGeneratorException("WorkerIdBitLength error.(range:[1, 21])"); | |||||
| } | |||||
| if (options.WorkerIdBitLength + options.SeqBitLength > 22) { | |||||
| throw new IdGeneratorException("error:WorkerIdBitLength + SeqBitLength <= 22"); | |||||
| } | |||||
| // 3.WorkerId | |||||
| int maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1; | |||||
| if (maxWorkerIdNumber == 0) { | |||||
| maxWorkerIdNumber = 63; | |||||
| } | |||||
| if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber) { | |||||
| string msg = "WorkerId error. (range:[0, " ~ to!string((maxWorkerIdNumber > 0 ? maxWorkerIdNumber : 63)) ~ "]"; | |||||
| throw new IdGeneratorException(msg); | |||||
| } | |||||
| // 4.SeqBitLength | |||||
| if (options.SeqBitLength < 2 || options.SeqBitLength > 21) { | |||||
| throw new IdGeneratorException("SeqBitLength error. (range:[2, 21])"); | |||||
| } | |||||
| // 5.MaxSeqNumber | |||||
| int maxSeqNumber = (1 << options.SeqBitLength) - 1; | |||||
| if (maxSeqNumber == 0) { | |||||
| maxSeqNumber = 63; | |||||
| } | |||||
| if (options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber) { | |||||
| throw new IdGeneratorException("MaxSeqNumber error. (range:[1, " ~ maxSeqNumber.to!string() ~ "]"); | |||||
| } | |||||
| // 6.MinSeqNumber | |||||
| if (options.MinSeqNumber < 5 || options.MinSeqNumber > maxSeqNumber) { | |||||
| throw new IdGeneratorException("MinSeqNumber error. (range:[5, " ~ maxSeqNumber.to!string() ~ "]"); | |||||
| } | |||||
| switch (options.Method) { | |||||
| case 2: | |||||
| _SnowWorker = new SnowWorkerM2(options); | |||||
| break; | |||||
| case 1: | |||||
| default: | |||||
| _SnowWorker = new SnowWorkerM1(options); | |||||
| break; | |||||
| } | |||||
| if (options.Method == 1) { | |||||
| try { | |||||
| Thread.sleep(500.msecs); | |||||
| } catch (Exception e) { | |||||
| writeln(e.toString()); | |||||
| } | |||||
| } | |||||
| } | |||||
| long newLong() { | |||||
| return _SnowWorker.nextId(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://gitee.com/yitter/idgenerator | |||||
| */ | |||||
| module yitter.idgen.YitIdHelper; | |||||
| import yitter.idgen.DefaultIdGenerator; | |||||
| import yitter.contract.IIdGenerator; | |||||
| import yitter.contract.IdGeneratorException; | |||||
| import yitter.contract.IdGeneratorOptions; | |||||
| import std.concurrency : initOnce; | |||||
| /** | |||||
| * 这是一个调用的例子,默认情况下,单机集成者可以直接使用 nextId()。 | |||||
| */ | |||||
| class YitIdHelper { | |||||
| private __gshared IIdGenerator idGenInstance = null; | |||||
| static IIdGenerator getIdGenInstance() { | |||||
| return initOnce!idGenInstance(new DefaultIdGenerator(new IdGeneratorOptions(1))); | |||||
| } | |||||
| /** | |||||
| * 设置参数,建议程序初始化时执行一次 | |||||
| */ | |||||
| static void setIdGenerator(IdGeneratorOptions options) { | |||||
| idGenInstance = new DefaultIdGenerator(options); | |||||
| } | |||||
| /** | |||||
| * 生成新的Id | |||||
| * 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。 | |||||
| * | |||||
| * @return | |||||
| */ | |||||
| static long nextId() { | |||||
| return getIdGenInstance().newLong(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| module yitter; | |||||
| public import yitter.contract; | |||||
| public import yitter.idgen.DefaultIdGenerator; | |||||
| public import yitter.idgen.YitIdHelper; | |||||
| @@ -0,0 +1,14 @@ | |||||
| { | |||||
| "authors": [ | |||||
| "yitter", | |||||
| "HuntLabs" | |||||
| ], | |||||
| "description": "A minimal D application.", | |||||
| "license": "proprietary", | |||||
| "name": "test", | |||||
| "dependencies": { | |||||
| "yitterd" : { | |||||
| "path": "../" | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,38 @@ | |||||
| module GenTest; | |||||
| import yitter.contract.IIdGenerator; | |||||
| import std.conv; | |||||
| import std.datetime; | |||||
| import std.stdio; | |||||
| class GenTest { | |||||
| private IIdGenerator IdGen; | |||||
| private int GenIdCount; | |||||
| private int WorkerId; | |||||
| this(IIdGenerator idGen, int genIdCount, int workerId) { | |||||
| GenIdCount = genIdCount; | |||||
| IdGen = idGen; | |||||
| WorkerId = workerId; | |||||
| } | |||||
| void GenStart() { | |||||
| MonoTime start = MonoTime.currTime(); | |||||
| long id = 0; | |||||
| for (int i = 0; i < GenIdCount; i++) { | |||||
| id = IdGen.newLong(); | |||||
| } | |||||
| MonoTime end = MonoTime.currTime(); | |||||
| Duration dur = end - start; | |||||
| // writeln(id); | |||||
| writeln("++++++++++++++++++++++++++++++++++++++++WorkerId: " | |||||
| ~ WorkerId.to!string() ~ ", total: " ~ dur.total!("msecs").to!string() ~ " ms"); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,52 @@ | |||||
| import std.stdio; | |||||
| import yitter; | |||||
| import GenTest; | |||||
| import core.thread; | |||||
| import std.conv; | |||||
| import std.datetime; | |||||
| import std.stdio; | |||||
| /** | |||||
| * 测试结果: | |||||
| * (1):1W并发,方法 1只要 1ms.而方法 2 要 180ms。 | |||||
| * (2):5W并发,方法 1只要 3ms.而方法 2 要 900ms。 | |||||
| * [不同CPU可能结果有差异,但相对大小不变] | |||||
| * 默认配置下,最佳性能是5W/s-8W/s | |||||
| */ | |||||
| enum int genIdCount = 50000; | |||||
| //1-漂移算法,2-传统算法 | |||||
| enum short method = 1; | |||||
| void main() | |||||
| { | |||||
| IdGeneratorOptions options = new IdGeneratorOptions(); | |||||
| options.Method = method; | |||||
| options.BaseTime = SysTime(DateTime(2020, 2, 20, 21, 51, 33)); | |||||
| options.WorkerId = 1; | |||||
| IIdGenerator idGen = new DefaultIdGenerator(options); | |||||
| GenTest.GenTest genTest = new GenTest.GenTest(idGen, genIdCount, options.WorkerId); | |||||
| // 首先测试一下 IdHelper 方法,获取单个Id | |||||
| YitIdHelper.setIdGenerator(options); | |||||
| long newId = YitIdHelper.nextId(); | |||||
| writeln("====================================="); | |||||
| writeln("这是用方法 " ~ method.to!string() ~ " 生成的 Id:" ~ newId.to!string()); | |||||
| // 然后循环测试一下,看看并发请求时的耗时情况 | |||||
| try { | |||||
| while (true) { | |||||
| genTest.GenStart(); | |||||
| // Thread.sleep(200.msecs); // 每隔1秒执行一次GenStart | |||||
| // writeln("Hello World! D"); | |||||
| } | |||||
| } catch (Exception e) { | |||||
| writeln(e.toString()); | |||||
| } | |||||
| } | |||||