@@ -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()); | |||||
} | |||||
} |