| @@ -257,3 +257,10 @@ target/ | |||
| # macOS | |||
| .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) | |||
| set(CMAKE_C_STANDARD 11) | |||
| @@ -8,6 +8,7 @@ set(CMAKE_C_STANDARD 11) | |||
| aux_source_directory(. DIR_SRCS) | |||
| add_subdirectory(idgen) | |||
| #编译动态库 | |||
| #set(LIB_SRC YitIdHelper.h YitIdHelper.c) | |||
| #add_library(YitIdGenLib SHARED ${LIB_SRC}) | |||
| @@ -21,7 +22,7 @@ add_subdirectory(idgen) | |||
| set(LIB_SRC YitIdHelper.h YitIdHelper.c) | |||
| add_library(YitIdHelper ${LIB_SRC}) | |||
| 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()); | |||
| } | |||
| } | |||