提交 58d62507 编写于 作者: Z zhouzj

auto commit

上级 e2dfceb5
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
*.editorconfig
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
**/.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
*.snupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# macOS
.DS_Store
## 运行环境
.NET Standard 2.0+
## 引用nuget包
```
<PackageReference Include="Yitter.IdGenerator" Version="1.0.*" />
```
## 调用示例
```
// 全局初始化设置WorkerId,默认最大2^16-1。(初始化过程全局只需一次,且必须最先设置)
var options = new IdGeneratorOptions(){ WorkerId = 1};
YitIdHelper.SetIdGenerator(options);
// 初始化以后,就可以在需要的地方调用方法生成ID。
var newId = YitIdHelper.NextId();
```
如果基于DI框架集成,可以参考 YitIdHelper 去管理 IdGenerator 对象,必须使用**单例**模式。
## options 默认值及说明
参考源码:/Contract/IdGeneratorOptions.cs
## 事件说明
1.IIdGenerator.GenIdActionAsync 是一个可以向外部系统异步发送ID生成消息的事件,它包含的消息类型有"漂移开始、漂移结束、时间回拨",具体参考 Yitter.IdGenTest 的 Program.cs 启动代码。不过订阅ID异步通知会有细微的性能损失。
2.你可在外部系统的异步(async标记)方法中调用本算法,同步调用同样没问题。
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
*.editorconfig
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
**/.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
*.snupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# macOS
.DS_Store

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31005.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yitter.IdGenerator", "Yitter.IdGenerator\Yitter.IdGenerator.csproj", "{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yitter.IdGenTest", "Yitter.IdGenTest\Yitter.IdGenTest.csproj", "{67426F7D-0A3B-4645-B4D7-5487215D3E2B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}.Release|Any CPU.Build.0 = Release|Any CPU
{67426F7D-0A3B-4645-B4D7-5487215D3E2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67426F7D-0A3B-4645-B4D7-5487215D3E2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67426F7D-0A3B-4645-B4D7-5487215D3E2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67426F7D-0A3B-4645-B4D7-5487215D3E2B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5C87B69B-CE8D-411F-AFAF-298C7BC7C2EA}
EndGlobalSection
EndGlobal
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Yitter.IdGenerator;
namespace Yitter.OrgSystem.TestA
{
public class GenTest
{
private IIdGenerator IdGen;
private Hashtable ids = new Hashtable();
public IList<long> idList = new List<long>();
private int GenIdCount;
private int WorkerId;
public GenTest(IIdGenerator idGen, int genIdCount, int workerId)
{
GenIdCount = genIdCount;
IdGen = idGen;
WorkerId = workerId;
}
//public void GenId()
//{
// Thread t = new Thread(new ThreadStart(Gen1Start));
// t.Start();
//}
public void GenStart()
{
DateTime start = DateTime.Now;
for (int i = 0; i < GenIdCount; i++)
{
var id = IdGen.NewLong();
//ids.Add(id, i);
//idList.Add(id);
}
DateTime end = DateTime.Now;
Console.WriteLine($"++++++++++++++++++++++++++++++++++++++++WorkerId: {WorkerId}, total: {(end - start).TotalMilliseconds} ms");
Interlocked.Increment(ref Program.Count);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using Yitter.IdGenerator;
namespace Yitter.OrgSystem.TestA
{
class Program
{
// 测试参数(默认配置下,最佳性能是10W/s)
static int genIdCount = 50000; // 计算ID数量(如果要验证50W效率,请将TopOverCostCount设置为20000或适当增加SeqBitLength)
static short method = 1; // 1-漂移算法,2-传统算法
static bool single = true;
static bool outputLog = false;
static IIdGenerator IdGen = null;
static IList<GenTest> testList = new List<GenTest>();
static bool checkResult = false;
public static int Count = 0;
static int workerCount = 1;
static void Main(string[] args)
{
Console.WriteLine("Hello World! C#");
var options = new IdGeneratorOptions()
{
Method = method,
WorkerId = 1,
WorkerIdBitLength = 6,
SeqBitLength = 6,
TopOverCostCount = 2000,
//MinSeqNumber = 1,
// MaxSeqNumber = 200,
// BaseTime = DateTime.Now.AddYears(-10),
};
IdGen = new DefaultIdGenerator(options);
GenTest genTest = new GenTest(IdGen, genIdCount, options.WorkerId);
// 首先测试一下 IdHelper 方法,获取单个Id
YitIdHelper.SetIdGenerator(options);
long newId = YitIdHelper.NextId();
Console.WriteLine("=====================================");
Console.WriteLine("这是用方法 " + method + " 生成的 Id:" + newId);
while (true)
{
//RunSingle();
// Go(options);
CallDll();
Thread.Sleep(1000); // 每隔1秒执行一次Go
}
}
[DllImport("yitidgenc.dll", CallingConvention = CallingConvention.StdCall)]
public static extern long NextId();
[DllImport("yitidgenc.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void SetWorkerId(uint workerId);
[DllImport("yitidgenc.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int TestId();
private static void CallDll()
{
try
{
int i = 0;
long id = 0;
DateTime start = DateTime.Now;
var ids = TestId();
//SetWorkerId(1);
while (i < 50000)
{
id = NextId();
i++;
}
DateTime end = DateTime.Now;
Console.WriteLine("id:" + id);
Console.WriteLine($"+++++++++++C# call rust dll, gen 5W, total: {(end - start).TotalMilliseconds} ms");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void RunSingle()
{
DateTime start = DateTime.Now;
for (int i = 0; i < genIdCount; i++)
{
var id = IdGen.NewLong();
}
DateTime end = DateTime.Now;
Console.WriteLine($"++++++++++++++++++++++++++++++++++++++++, total: {(end - start).TotalMilliseconds} ms");
Interlocked.Increment(ref Program.Count);
}
private static void Go(IdGeneratorOptions options)
{
Count = 0;
testList = new List<GenTest>();
// ++++++++++++++++++++++++++++++++
if (single)
{
if (IdGen == null)
{
IdGen = new DefaultIdGenerator(options);
}
if (outputLog)
{
IdGen.GenIdActionAsync = (arg =>
{
if (arg.ActionType == 1)
{
Console.WriteLine($">>>> {arg.WorkerId}:开始:{DateTime.Now.ToString("mm:ss:fff")}, 周期次序:{arg.TermIndex}");
}
else if (arg.ActionType == 2)
{
Console.WriteLine($"<<<< {arg.WorkerId}:结束:{DateTime.Now.ToString("mm:ss:fff")},漂移 {arg.OverCostCountInOneTerm} 次,产生 {arg.GenCountInOneTerm} 个, 周期次序:{arg.TermIndex}");
}
if (arg.ActionType == 8)
{
Console.WriteLine($"---- {arg.WorkerId}:AA结束:{DateTime.Now.ToString("mm:ss:fff")},时间回拨");
}
});
}
for (int i = 1; i < workerCount + 1; i++)
{
Console.WriteLine("Gen:" + i);
var test = new GenTest(IdGen, genIdCount, i);
testList.Add(test);
// test.GenId();
test.GenStart();
}
}
else
{
for (int i = 1; i < workerCount + 1; i++)
{
IdGeneratorOptions newOptions = new IdGeneratorOptions()
{
WorkerId = (ushort)i, // workerId 不能设置为0
WorkerIdBitLength = options.WorkerIdBitLength,
SeqBitLength = options.SeqBitLength,
MinSeqNumber = options.MinSeqNumber,
MaxSeqNumber = options.MaxSeqNumber,
Method = options.Method,
};
Console.WriteLine("Gen:" + i);
var idGen2 = new DefaultIdGenerator(newOptions);
var test = new GenTest(idGen2, genIdCount, i);
if (outputLog)
{
idGen2.GenIdActionAsync = (arg =>
{
Console.WriteLine($"{DateTime.Now.ToString("mm:ss:fff")} {arg.WorkerId} 漂移了 {arg.OverCostCountInOneTerm}, 顺序:{arg.TermIndex}");
});
}
testList.Add(test);
// test.GenId();
test.GenStart();
}
}
while (Count < workerCount)
{
//Console.WriteLine("Count:" + Count);
Thread.Sleep(1000);
}
//Console.WriteLine("Count:" + Count);
if (!checkResult)
{
return;
}
var dupCount = 0;
foreach (var id in testList[0].idList)
{
if (id == 0)
{
Console.WriteLine("############### 错误的ID:" + id + "###########");
}
for (int j = 1; j < testList.Count; j++)
{
if (testList[j].idList.Contains(id))
{
dupCount++;
Console.WriteLine("xxxxxxxxxx 重复的ID:" + id);
}
}
}
if (dupCount > 0)
{
Console.WriteLine($"重复数量:{dupCount}");
}
}
}
}
{
"profiles": {
"Yitter.IdGenTest": {
"commandName": "Project",
"nativeDebugging": true
}
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>1.0.2</Version>
<PackageProjectUrl>https://gitee.com/yitter/idgenerator</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Yitter.IdGenerator\Yitter.IdGenerator.csproj" />
</ItemGroup>
</Project>
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
* 版权协议:MIT
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
*/
using System;
namespace Yitter.IdGenerator
{
public interface IIdGenerator
{
/// <summary>
/// 生成过程中产生的事件
/// </summary>
Action<OverCostActionArg> GenIdActionAsync { get; set; }
/// <summary>
/// 生成新的long型Id
/// </summary>
/// <returns></returns>
long NewLong();
// Guid NewGuid();
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
* 版权协议:MIT
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Yitter.IdGenerator
{
internal interface ISnowWorker
{
Action<OverCostActionArg> GenAction { get; set; }
long NextId();
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
* 版权协议:MIT
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Yitter.IdGenerator
{
public class IdGeneratorOptions
{
/// <summary>
/// 雪花计算方法
/// (1-漂移算法|2-传统算法),默认1
/// </summary>
public virtual short Method { get; set; } = 1;
/// <summary>
/// 基础时间(UTC格式)
/// 不能超过当前系统时间
/// </summary>
public virtual DateTime BaseTime { get; set; } = new DateTime(2020, 2, 20, 2, 20, 2, 20, DateTimeKind.Utc);
/// <summary>
/// 机器码
/// 与 WorkerIdBitLength 有关系
/// (ushort类型,最大值65535,如果有更高要求,请修改数据类型,或联系作者)
/// </summary>
public virtual ushort WorkerId { get; set; } = 0;
/// <summary>
/// 机器码位长
/// 范围:1-21(要求:序列数位长+机器码位长不超过22)。
/// 建议范围:6-12。
/// </summary>
public virtual byte WorkerIdBitLength { get; set; } = 6;//10;
/// <summary>
/// 序列数位长
/// 范围:2-21(要求:序列数位长+机器码位长不超过22)。
/// 建议范围:6-14。
/// </summary>
public virtual byte SeqBitLength { get; set; } = 6;//10;
/// <summary>
/// 最大序列数(含)
/// (由SeqBitLength计算的最大值)
/// </summary>
public virtual int MaxSeqNumber { get; set; } = 0;
/// <summary>
/// 最小序列数(含)
/// 默认5,不小于1,不大于MaxSeqNumber
/// </summary>
public virtual ushort MinSeqNumber { get; set; } = 5;
/// <summary>
/// 最大漂移次数(含),
/// 默认2000,推荐范围500-10000(与计算能力有关)
/// </summary>
public virtual int TopOverCostCount { get; set; } = 2000;
public IdGeneratorOptions()
{
}
public IdGeneratorOptions(ushort workerId)
{
WorkerId = workerId;
}
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
* 版权协议:MIT
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Yitter.IdGenerator
{
/// <summary>
/// Id生成时回调参数
/// </summary>
public class OverCostActionArg
{
/// <summary>
/// 事件类型
/// 1-开始,2-结束,8-漂移
/// </summary>
public virtual int ActionType { get; set; }
/// <summary>
/// 时间戳
/// </summary>
public virtual long TimeTick { get; set; }
/// <summary>
/// 机器码
/// </summary>
public virtual ushort WorkerId { get; set; }
/// <summary>
/// 漂移计算次数
/// </summary>
public virtual int OverCostCountInOneTerm { get; set; }
/// <summary>
/// 漂移期间生产ID个数
/// </summary>
public virtual int GenCountInOneTerm { get; set; }
/// <summary>
/// 漂移周期
/// </summary>
public virtual int TermIndex { get; set; }
public OverCostActionArg(ushort workerId, long timeTick, int actionType = 0, int overCostCountInOneTerm = 0, int genCountWhenOverCost = 0, int index = 0)
{
ActionType = actionType;
TimeTick = timeTick;
WorkerId = workerId;
OverCostCountInOneTerm = overCostCountInOneTerm;
GenCountInOneTerm = genCountWhenOverCost;
TermIndex = index;
}
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
* 版权协议:MIT
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
*/
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Yitter.IdGenerator
{
/// <summary>
/// 雪花漂移算法
/// </summary>
internal class SnowWorkerM1 : ISnowWorker
{
/// <summary>
/// 基础时间
/// </summary>
protected readonly DateTime BaseTime;
/// <summary>
/// 机器码
/// </summary>
protected readonly ushort WorkerId = 0;
/// <summary>
/// 机器码位长
/// </summary>
protected readonly byte WorkerIdBitLength = 0;
/// <summary>
/// 自增序列数位长
/// </summary>
protected readonly byte SeqBitLength = 0;
/// <summary>
/// 最大序列数(含)
/// </summary>
protected readonly int MaxSeqNumber = 0;
/// <summary>
/// 最小序列数(含)
/// </summary>
protected readonly ushort MinSeqNumber = 0;
/// <summary>
/// 最大漂移次数
/// </summary>
protected readonly int TopOverCostCount = 0;
protected readonly byte _TimestampShift = 0;
protected static object _SyncLock = new object();
protected ushort _CurrentSeqNumber;
protected long _LastTimeTick = -1L;
protected long _TurnBackTimeTick = -1L;
protected byte _TurnBackIndex = 0;
protected bool _IsOverCost = false;
protected int _OverCostCountInOneTerm = 0;
protected int _GenCountInOneTerm = 0;
protected int _TermIndex = 0;
//private static long _StartTimeTick = 0;
//private static long _BaseTimeTick = 0;
public Action<OverCostActionArg> GenAction { get; set; }
public SnowWorkerM1(IdGeneratorOptions options)
{
WorkerId = options.WorkerId;
WorkerIdBitLength = options.WorkerIdBitLength;
SeqBitLength = options.SeqBitLength;
MaxSeqNumber = options.MaxSeqNumber;
MinSeqNumber = options.MinSeqNumber;
TopOverCostCount = options.TopOverCostCount;
if (options.BaseTime != DateTime.MinValue)
{
BaseTime = options.BaseTime;
}
if (WorkerId < 1)
{
WorkerId = (ushort)DateTime.Now.Millisecond;
}
if (SeqBitLength == 0)
{
SeqBitLength = 6;
}
if (WorkerIdBitLength == 0)
{
WorkerIdBitLength = 6;
}
if (MaxSeqNumber == 0)
{
MaxSeqNumber = (1 << SeqBitLength) - 1;
}
_TimestampShift = (byte)(WorkerIdBitLength + SeqBitLength);
_CurrentSeqNumber = options.MinSeqNumber;
//_BaseTimeTick = BaseTime.Ticks;
//_StartTimeTick = (long)(DateTime.UtcNow.Subtract(BaseTime).TotalMilliseconds) - Environment.TickCount;
}
private void DoGenIdAction(OverCostActionArg arg)
{
Task.Run(() =>
{
GenAction(arg);
});
}
private void BeginOverCostAction(in long useTimeTick)
{
return;
if (GenAction == null)
{
return;
}
DoGenIdAction(new OverCostActionArg(
WorkerId,
useTimeTick,
1,
_OverCostCountInOneTerm,
_GenCountInOneTerm,
_TermIndex));
}
private void EndOverCostAction(in long useTimeTick)
{
if (_TermIndex > 10000)
{
_TermIndex = 0;
}
return;
if (GenAction == null)
{
return;
}
DoGenIdAction(new OverCostActionArg(
WorkerId,
useTimeTick,
2,
_OverCostCountInOneTerm,
_GenCountInOneTerm,
_TermIndex));
}
private void BeginTurnBackAction(in long useTimeTick)
{
return;
if (GenAction == null)
{
return;
}
DoGenIdAction(new OverCostActionArg(
WorkerId,
useTimeTick,
8,
0,
0,
_TurnBackIndex));
}
private void EndTurnBackAction(in long useTimeTick)
{
return;
if (GenAction == null)
{
return;
}
DoGenIdAction(new OverCostActionArg(
WorkerId,
useTimeTick,
9,
0,
0,
_TurnBackIndex));
}
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);
}
Thread.Sleep(10);
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(in long useTimeTick)
{
var result = ((useTimeTick << _TimestampShift) +
((long)WorkerId << SeqBitLength) +
(uint)_CurrentSeqNumber);
_CurrentSeqNumber++;
return result;
}
private long CalcTurnBackId(in long useTimeTick)
{
var result = ((useTimeTick << _TimestampShift) +
((long)WorkerId << SeqBitLength) + _TurnBackIndex);
_TurnBackTimeTick--;
return result;
}
protected virtual long GetCurrentTimeTick()
{
//return (long)(DateTime.UtcNow - BaseTime).Ticks;
//return (long)(_StartTimeTick + Environment.TickCount);
return (long)(DateTime.UtcNow - BaseTime).TotalMilliseconds;
}
protected virtual long GetNextTimeTick()
{
long tempTimeTicker = GetCurrentTimeTick();
while (tempTimeTicker <= _LastTimeTick)
{
tempTimeTicker = GetCurrentTimeTick();
}
return tempTimeTicker;
}
public virtual long NextId()
{
lock (_SyncLock)
{
return _IsOverCost ? NextOverCostId() : NextNormalId();
}
}
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
* 版权协议:MIT
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Yitter.IdGenerator
{
/// <summary>
/// 常规雪花算法
/// </summary>
internal class SnowWorkerM2 : SnowWorkerM1
{
public SnowWorkerM2(IdGeneratorOptions options) : base(options)
{
}
public override long NextId()
{
lock (_SyncLock)
{
long currentTimeTick = GetCurrentTimeTick();
if (_LastTimeTick == currentTimeTick)
{
if (_CurrentSeqNumber++ > MaxSeqNumber)
{
_CurrentSeqNumber = MinSeqNumber;
currentTimeTick = GetNextTimeTick();
}
}
else
{
_CurrentSeqNumber = MinSeqNumber;
}
if (currentTimeTick < _LastTimeTick)
{
throw new Exception(string.Format("Time error for {0} milliseconds", _LastTimeTick - currentTimeTick));
}
_LastTimeTick = currentTimeTick;
var result = ((currentTimeTick << _TimestampShift) + ((long)WorkerId << SeqBitLength) + (uint)_CurrentSeqNumber);
return result;
}
}
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
* 版权协议:MIT
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Yitter.IdGenerator
{
/// <summary>
/// 默认实现
/// </summary>
public class DefaultIdGenerator : IIdGenerator
{
private ISnowWorker _SnowWorker { get; set; }
public Action<OverCostActionArg> GenIdActionAsync
{
get => _SnowWorker.GenAction;
set => _SnowWorker.GenAction = value;
}
public DefaultIdGenerator(IdGeneratorOptions options)
{
if (options == null)
{
throw new ApplicationException("options error.");
}
if (options.BaseTime < DateTime.Now.AddYears(-50) || options.BaseTime > DateTime.Now)
{
throw new ApplicationException("BaseTime error.");
}
if (options.WorkerIdBitLength <= 0)
{
throw new ApplicationException("WorkerIdBitLength error.(range:[1, 21])");
}
if (options.SeqBitLength + options.WorkerIdBitLength > 22)
{
throw new ApplicationException("error:WorkerIdBitLength + SeqBitLength <= 22");
}
var maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1;
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber)
{
throw new ApplicationException("WorkerId error. (range:[0, " + (maxWorkerIdNumber > 0 ? maxWorkerIdNumber : 63) + "]");
}
if (options.SeqBitLength < 2 || options.SeqBitLength > 21)
{
throw new ApplicationException("SeqBitLength error. (range:[2, 21])");
}
var maxSeqNumber = (1 << options.SeqBitLength) - 1;
if (options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber)
{
throw new ApplicationException("MaxSeqNumber error. (range:[1, " + maxSeqNumber + "]");
}
var maxValue = maxSeqNumber;
if (options.MinSeqNumber < 1 || options.MinSeqNumber > maxValue)
{
throw new ApplicationException("MinSeqNumber error. (range:[1, " + maxValue + "]");
}
switch (options.Method)
{
case 1:
_SnowWorker = new SnowWorkerM1(options);
break;
case 2:
_SnowWorker = new SnowWorkerM2(options);
break;
default:
_SnowWorker = new SnowWorkerM1(options);
break;
}
if (options.Method == 1)
{
Thread.Sleep(500);
}
}
public long NewLong()
{
return _SnowWorker.NextId();
}
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
* 版权协议:MIT
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Yitter.IdGenerator
{
/// <summary>
/// 这是一个调用的例子,默认情况下,单机集成者可以直接使用 NextId()。
/// </summary>
public class YitIdHelper
{
private static IIdGenerator _IdGenInstance = null;
public static IIdGenerator IdGenInstance => _IdGenInstance;
/// <summary>
/// 设置参数,建议程序初始化时执行一次
/// </summary>
/// <param name="options"></param>
public static void SetIdGenerator(IdGeneratorOptions options)
{
_IdGenInstance = new DefaultIdGenerator(options);
}
/// <summary>
/// 生成新的Id
/// 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。
/// 否则将会初始化一个WorkerId为1的对象。
/// </summary>
/// <returns></returns>
public static long NextId()
{
if (_IdGenInstance == null)
{
_IdGenInstance = new DefaultIdGenerator(
new IdGeneratorOptions() { WorkerId = 1 }
);
}
return _IdGenInstance.NewLong();
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Description>Shorter ID and faster generation with a new snowflake drift algorithm. The core is to shorten the ID length, but also can have a very high instantaneous concurrent processing capacity (50W/0.1s), and powerful configuration capacity.
一种全新的雪花漂移算法,让ID更短、生成速度更快。 核心在于缩短ID长度的同时,还能拥有极高瞬时并发处理量(50W/0.1s),及强大的配置能力。</Description>
<AssemblyName>Yitter.IdGenerator</AssemblyName>
<RootNamespace>Yitter.IdGenerator</RootNamespace>
<Product>IdGenerator</Product>
<Company>Yitter</Company>
<Authors>Yitter</Authors>
<Copyright>Yitter</Copyright>
<PackageProjectUrl>https://gitee.com/yitter/idgenerator</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Version>1.0.9</Version>
<PackageReleaseNotes></PackageReleaseNotes>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<WarningLevel>5</WarningLevel>
</PropertyGroup>
</Project>
# idgenerator
## 编译说明
1.默认是 Linux 环境,用 CMake。
2.如果是 Windows 环境,要用 Cygwin 或 MinGW。
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
*.editorconfig
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
**/.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
*.snupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
target/
cmake-build*/
# macOS
.DS_Store
cmake_minimum_required(VERSION 3.17)
project(YitIdGen)
set(CMAKE_C_STANDARD 11)
#set(CMAKE_BUILD_TYPE DEBUG)
#set(CMAKE_BUILD_TYPE RELEASE)
aux_source_directory(. DIR_SRCS)
add_subdirectory(idgen)
#编译动态库
set(LIB_SRC YitIdHelper.h YitIdHelper.c)
add_library(YitIdGenLib SHARED ${LIB_SRC})
target_link_libraries(YitIdGenLib idgen)
set_target_properties(YitIdGenLib PROPERTIES
LINKER_LANGUAGE C
OUTPUT_NAME "yitidgenc"
PREFIX "")
##编译执行文件
#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)
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#include <stdlib.h>
#include <stdint.h>
#include "YitIdHelper.h"
#include "idgen/IdGenerator.h"
extern void SetIdGenerator(IdGeneratorOptions options) {
SetOptions(options);
}
extern void SetWorkerId(uint32_t workerId) {
IdGeneratorOptions options = BuildIdGenOptions(workerId);
// SetOptions(options);
SetIdGenerator(options);
}
extern uint64_t NextId() {
return GetIdGenInstance()->NextId();
// IdGenerator *generator = GetIdGenInstance();
// uint64_t id = generator->NextId();
// free(generator);
// return id;
}
extern uint64_t TestId() {
return 123456;
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#pragma once
#include "idgen/IdGenOptions.h"
#include "idgen/common.h"
TAP_DLLEXPORT
extern void TAP_STDCALL SetIdGenerator(IdGeneratorOptions options);
TAP_DLLEXPORT
extern void TAP_STDCALL SetWorkerId(uint32_t workerId);
TAP_DLLEXPORT
extern uint64_t TAP_STDCALL NextId();
TAP_DLLEXPORT
extern uint64_t TAP_STDCALL TestId();
aux_source_directory(. DIR_LIB_SRCS)
add_library(idgen ${DIR_LIB_SRCS})
#SET(LIB_SRC ../YitIdHelper.h ../YitIdHelper.c)
#add_library(YitIdGenLib SHARED ${LIB_SRC})
#target_link_libraries(YitIdGenLib IdGen)
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#include "IdGenOptions.h"
extern IdGeneratorOptions BuildIdGenOptions(uint32_t workerId) {
IdGeneratorOptions options;
options.Method = 1;
options.BaseTime = 1582136402000;
options.WorkerId = workerId;
options.WorkerIdBitLength = 6;
options.SeqBitLength = 6;
options.MaxSeqNumber = 0;
options.MinSeqNumber = 5;
options.TopOverCostCount = 2000;
return options;
// IdGeneratorOptions *options = (IdGeneratorOptions *) malloc(sizeof(IdGeneratorOptions));
//
// options->Method = 1;
// options->BaseTime = 1582136402000;
// options->WorkerId = workerId;
// options->WorkerIdBitLength = 6;
// options->SeqBitLength = 6;
// options->MaxSeqNumber = 63;
// options->MinSeqNumber = 5;
// options->TopOverCostCount = 2000;
//
// return options;
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#pragma once
#include <stdint.h>
typedef struct IdGenOptions {
/// 雪花计算方法,(1-漂移算法|2-传统算法),默认1
uint8_t Method;
/// 基础时间(ms单位),不能超过当前系统时间
uint64_t BaseTime;
/// 机器码,与 WorkerIdBitLength 有关系
uint32_t WorkerId;
/// 机器码位长,范围:1-21(要求:序列数位长+机器码位长不超过22)
uint8_t WorkerIdBitLength;
/// 序列数位长,范围:2-21(要求:序列数位长+机器码位长不超过22)
uint8_t SeqBitLength;
/// 最大序列数(含),(由 SeqBitLength 计算的最大值)
uint32_t MaxSeqNumber;
/// 最小序列数(含),默认5,不小于5,不大于 MaxSeqNumber
uint32_t MinSeqNumber;
/// 最大漂移次数(含),默认2000,推荐范围 500-20000(与计算能力有关)
uint32_t TopOverCostCount;
} IdGeneratorOptions;
extern IdGeneratorOptions BuildIdGenOptions(uint32_t workerId);
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#include <stdio.h>
#include <malloc.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include "IdGenerator.h"
static inline uint64_t WorkerM1Id() {
return WorkerM1NextId(_idGenerator->Worker);
}
static inline uint64_t WorkerM2Id() {
return WorkerM2NextId(_idGenerator->Worker);
}
extern IdGenerator *GetIdGenInstance() {
if (_idGenerator != NULL)
return _idGenerator;
else {
_idGenerator = (IdGenerator *) malloc(sizeof(IdGenerator));
_idGenerator->Worker = NewSnowFlakeWorker();
return _idGenerator;
}
}
extern void SetOptions(IdGeneratorOptions options) {
if (GetIdGenInstance() == NULL) {
exit(1);
}
// BaseTime
if (options.BaseTime == 0) {
_idGenerator->Worker->BaseTime = 1582136402000;
} else if (options.BaseTime < 631123200000 || options.BaseTime > GetCurrentTime()) {
perror("BaseTime error.");
exit(1);
} else {
_idGenerator->Worker->BaseTime = options.BaseTime;
}
// WorkerIdBitLength
if (options.WorkerIdBitLength <= 0) {
perror("WorkerIdBitLength error.(range:[1, 21])");
exit(1);
}
if (options.SeqBitLength + options.WorkerIdBitLength > 22) {
perror("error:WorkerIdBitLength + SeqBitLength <= 22");
exit(1);
} else {
// _idGenerator->Worker->WorkerIdBitLength = options.WorkerIdBitLength;
_idGenerator->Worker->WorkerIdBitLength = options.WorkerIdBitLength <= 0 ? 6 : options.WorkerIdBitLength;
}
// WorkerId
uint32_t maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1;
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber) {
perror("WorkerId error. (range:[0, {2^options.WorkerIdBitLength-1]}");
exit(1);
} else {
_idGenerator->Worker->WorkerId = options.WorkerId;
}
// SeqBitLength
if (options.SeqBitLength < 2 || options.SeqBitLength > 21) {
perror("SeqBitLength error. (range:[2, 21])");
exit(1);
} else {
// _idGenerator->Worker->SeqBitLength = options.SeqBitLength;
_idGenerator->Worker->SeqBitLength = options.SeqBitLength <= 0 ? 6 : options.SeqBitLength;
}
// MaxSeqNumber
uint32_t maxSeqNumber = (1 << options.SeqBitLength) - 1;
if (options.MaxSeqNumber > maxSeqNumber) {
perror("MaxSeqNumber error. (range:[1, {2^options.SeqBitLength-1}]");
exit(1);
} else {
_idGenerator->Worker->MaxSeqNumber = options.MaxSeqNumber <= 0 ? maxSeqNumber : options.MaxSeqNumber;
}
// MinSeqNumber
if (options.MinSeqNumber > maxSeqNumber || options.MinSeqNumber < 5) {
perror("MinSeqNumber error. (range:[5, {options.MinSeqNumber}]");
exit(1);
} else {
_idGenerator->Worker->MinSeqNumber = options.MinSeqNumber <= 0 ? 5 : options.MinSeqNumber;
}
_idGenerator->Worker->TopOverCostCount = options.TopOverCostCount <= 0 ? 2000 : options.TopOverCostCount;
_idGenerator->Worker->_TimestampShift = options.WorkerIdBitLength + options.SeqBitLength;
_idGenerator->Worker->_CurrentSeqNumber = options.MinSeqNumber;
_idGenerator->Worker->Method = options.Method;
if (options.Method == 2) {
_idGenerator->NextId = WorkerM2Id;
} else {
_idGenerator->NextId = WorkerM1Id;
sleep(1);
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#pragma once
#include <stdio.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "IdGenOptions.h"
#include "SnowWorkerM1.h"
#include "SnowWorkerM2.h"
typedef struct IdGenerator {
SnowFlakeWorker *Worker;
uint64_t (*NextId)();
} IdGenerator;
static IdGenerator *_idGenerator = NULL;
extern IdGenerator *GetIdGenInstance();
extern void SetOptions(IdGeneratorOptions options);
/*
* 版权属于:yitter(yitter@126.com)
* 代码翻译:amuluowin
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#include <malloc.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include "SnowWorkerM1.h"
pthread_mutex_t ThreadMutex = PTHREAD_MUTEX_INITIALIZER;
static void EndOverCostAction(uint64_t useTimeTick, SnowFlakeWorker *worker);
static uint64_t NextOverCostId(SnowFlakeWorker *worker);
static uint64_t NextNormalId(SnowFlakeWorker *worker);
static uint64_t CalcId(SnowFlakeWorker *worker);
static uint64_t CalcTurnBackId(SnowFlakeWorker *worker);
static inline void EndOverCostAction(uint64_t useTimeTick, SnowFlakeWorker *worker) {
if (worker->_TermIndex > 10000) {
worker->_TermIndex = 0;
}
}
static inline uint64_t NextOverCostId(SnowFlakeWorker *worker) {
uint64_t currentTimeTick = GetCurrentTimeTick(worker);
if (currentTimeTick > worker->_LastTimeTick) {
EndOverCostAction(currentTimeTick, worker);
worker->_LastTimeTick = currentTimeTick;
worker->_CurrentSeqNumber = worker->MinSeqNumber;
worker->_IsOverCost = false;
worker->_OverCostCountInOneTerm = 0;
worker->_GenCountInOneTerm = 0;
return CalcId(worker);
}
if (worker->_OverCostCountInOneTerm > worker->TopOverCostCount) {
EndOverCostAction(currentTimeTick, worker);
worker->_LastTimeTick = GetNextTimeTick(worker);
worker->_CurrentSeqNumber = worker->MinSeqNumber;
worker->_IsOverCost = false;
worker->_OverCostCountInOneTerm = 0;
worker->_GenCountInOneTerm = 0;
return CalcId(worker);
}
if (worker->_CurrentSeqNumber > worker->MaxSeqNumber) {
worker->_LastTimeTick++;
worker->_CurrentSeqNumber = worker->MinSeqNumber;
worker->_IsOverCost = true;
worker->_OverCostCountInOneTerm++;
worker->_GenCountInOneTerm++;
return CalcId(worker);
}
worker->_GenCountInOneTerm++;
return CalcId(worker);
}
static inline uint64_t NextNormalId(SnowFlakeWorker *worker) {
uint64_t currentTimeTick = GetCurrentTimeTick(worker);
if (currentTimeTick < worker->_LastTimeTick) {
if (worker->_TurnBackTimeTick < 1) {
worker->_TurnBackTimeTick = worker->_LastTimeTick - 1;
worker->_TurnBackIndex++;
if (worker->_TurnBackIndex > 4) {
worker->_TurnBackIndex = 1;
}
}
return CalcTurnBackId(worker);
}
if (worker->_TurnBackTimeTick > 0) {
worker->_TurnBackTimeTick = 0;
}
if (currentTimeTick > worker->_LastTimeTick) {
worker->_LastTimeTick = currentTimeTick;
worker->_CurrentSeqNumber = worker->MinSeqNumber;
return CalcId(worker);
}
if (worker->_CurrentSeqNumber > worker->MaxSeqNumber) {
worker->_TermIndex++;
worker->_LastTimeTick++;
worker->_CurrentSeqNumber = worker->MinSeqNumber;
worker->_IsOverCost = true;
worker->_OverCostCountInOneTerm = 1;
worker->_GenCountInOneTerm = 1;
return CalcId(worker);
}
return CalcId(worker);
}
static inline uint64_t CalcId(SnowFlakeWorker *worker) {
uint64_t result = (worker->_LastTimeTick << worker->_TimestampShift) | (worker->WorkerId << worker->SeqBitLength) |
(worker->_CurrentSeqNumber);
worker->_CurrentSeqNumber++;
return result;
}
static inline uint64_t CalcTurnBackId(SnowFlakeWorker *worker) {
uint64_t result = (worker->_LastTimeTick << worker->_TimestampShift) | (worker->WorkerId << worker->SeqBitLength) |
(worker->_TurnBackTimeTick);
worker->_TurnBackTimeTick--;
return result;
}
extern SnowFlakeWorker *NewSnowFlakeWorker() {
SnowFlakeWorker *worker = (SnowFlakeWorker *) malloc(sizeof(SnowFlakeWorker));
worker->_IsOverCost = false;
worker->_LastTimeTick = 0;
worker->_TurnBackTimeTick = 0;
worker->_TurnBackIndex = 0;
worker->_OverCostCountInOneTerm = 0;
worker->_GenCountInOneTerm = 0;
worker->_TermIndex = 0;
return worker;
}
extern uint64_t WorkerM1NextId(SnowFlakeWorker *worker) {
pthread_mutex_lock(&ThreadMutex);
uint64_t id = worker->_IsOverCost ? NextOverCostId(worker) : NextNormalId(worker);
pthread_mutex_unlock(&ThreadMutex);
return id;
}
extern uint64_t GetCurrentTimeTick(SnowFlakeWorker *worker) {
struct timeval tv;
gettimeofday(&tv, NULL);
return ((uint64_t) tv.tv_sec * 1000 + tv.tv_usec / 1000 - worker->BaseTime);
}
extern uint64_t GetCurrentTime() {
struct timeval tv;
gettimeofday(&tv, NULL);
return ((uint64_t) (tv.tv_sec)) * 1000 + tv.tv_usec / 1000;
//static struct timeb t1;
// ftime(&t1);
// return (uint64_t) ((t1.time * 1000 + t1.millitm));
}
extern uint64_t GetCurrentMicroTime() {
struct timeval tv;
gettimeofday(&tv, NULL);
return ((uint64_t) tv.tv_sec * 1000000 + tv.tv_usec);
}
extern uint64_t GetNextTimeTick(SnowFlakeWorker *worker) {
uint64_t tempTimeTicker = GetCurrentTimeTick(worker);
while (tempTimeTicker <= worker->_LastTimeTick) {
tempTimeTicker = GetCurrentTimeTick(worker);
}
return tempTimeTicker;
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码翻译:amuluowin
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#pragma once
#include <stdlib.h>
#include <stdint.h>
#include <sys/timeb.h>
#include <pthread.h>
#include <stdbool.h>
#include "IdGenOptions.h"
extern pthread_mutex_t ThreadMutex;
typedef struct SnowFlakeWorker {
uint8_t Method;
uint64_t BaseTime;
uint32_t WorkerId;
uint8_t WorkerIdBitLength;
uint8_t SeqBitLength;
uint32_t MaxSeqNumber;
uint32_t MinSeqNumber;
uint32_t TopOverCostCount;
uint8_t _TimestampShift;
uint32_t _CurrentSeqNumber;
int64_t _LastTimeTick;
int64_t _TurnBackTimeTick;
uint8_t _TurnBackIndex;
bool _IsOverCost;
uint32_t _OverCostCountInOneTerm;
uint32_t _GenCountInOneTerm;
uint32_t _TermIndex;
} SnowFlakeWorker;
extern SnowFlakeWorker *NewSnowFlakeWorker();
extern uint64_t WorkerM1NextId(SnowFlakeWorker *worker);
extern uint64_t GetCurrentTimeTick(SnowFlakeWorker *worker);
extern uint64_t GetNextTimeTick(SnowFlakeWorker *worker);
extern uint64_t GetCurrentTime();
extern uint64_t GetCurrentMicroTime();
/*
* 版权属于:yitter(yitter@126.com)
* 代码翻译:amuluowin
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#include <malloc.h>
#include <stdlib.h>
#include <pthread.h>
#include "SnowWorkerM2.h"
extern uint64_t WorkerM2NextId(SnowFlakeWorker *worker) {
pthread_mutex_lock(&ThreadMutex);
uint64_t currentTimeTick = GetCurrentTimeTick(worker);
if (worker->_LastTimeTick == currentTimeTick) {
worker->_CurrentSeqNumber = (++worker->_CurrentSeqNumber) & worker->MaxSeqNumber;
if (worker->_CurrentSeqNumber == 0) {
currentTimeTick = GetNextTimeTick(worker);
}
} else {
worker->_CurrentSeqNumber = worker->MinSeqNumber;
}
worker->_LastTimeTick = currentTimeTick;
uint64_t id = (uint64_t) ((currentTimeTick << worker->_TimestampShift) |
(worker->WorkerId << worker->SeqBitLength) |
worker->_CurrentSeqNumber);
pthread_mutex_unlock(&ThreadMutex);
return id;
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码翻译:amuluowin
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#pragma once
#include <stdlib.h>
#include "SnowWorkerM1.h"
extern uint64_t WorkerM2NextId(SnowFlakeWorker *worker);
//
// Created by zhouzj on 2021/3/28.
//
#pragma once
#ifdef _WIN32
#define TAP_CDECL __cdecl
#define TAP_STDCALL __stdcall
#define TAP_DLLEXPORT __declspec(dllexport)
#else
#define TAP_CDECL
#define TAP_STDCALL
#define TAP_DLLEXPORT
#endif
/*
* 版权属于:yitter(yitter@126.com)
* 代码翻译:amuluowin
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/timeb.h>
#include <pthread.h>
#include <unistd.h>
#include <stdbool.h>
#include "idgen/SnowWorkerM1.h"
#include "idgen/IdGenerator.h"
#include "YitIdHelper.h"
const int GenIdCount = 50000;
const bool multiThread = false;
const int threadCount = 50;
const int method = 1;
void RunMultiThread() {
//int64_t start = GetCurrentMicroTime();
for (int i = 0; i < GenIdCount / threadCount; i++) {
int64_t id = NextId();
printf("生成ID: %D\n", id);
}
int64_t end = GetCurrentMicroTime();
//printf("%s,total:%d μs\n", method == 1 ? "1" : "2", (end - start));
}
void RunSingle() {
int64_t start = GetCurrentMicroTime();
for (int i = 0; i < GenIdCount; i++) {
int64_t id = NextId();
// printf("生成ID: %ld\n", id);
}
int64_t end = GetCurrentMicroTime();
printf("%s,total:%d μs\n", method == 1 ? "1" : "2", (end - start));
}
int main() {
IdGeneratorOptions options = BuildIdGenOptions(1);
options.Method = method;
options.WorkerId = 1;
options.SeqBitLength = 6;
SetIdGenerator(options);
pthread_t tid[threadCount];
while (1) {
if (multiThread) {
for (int i = 0; i < threadCount; i++) {
if (pthread_create(&tid[i], NULL, (void *) RunMultiThread, NULL) != 0) {
printf("thread creation failed\n");
exit(1);
}
}
} else {
RunSingle();
}
sleep(1);
}
}
# idgenerator
## Go环境
1.SDK,go1.16
2.启用 Go-Modules
```
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,https://goproxy.io,direct
```
## Go代码示例
```
var yid = idgen.YitIdHelper{}
fmt.Println(yid.NextId())
// 方法二:自定义参数
var options = contract.NewIdGeneratorOptions(1)
//options.WorkerIdBitLength = 6
//options.SeqBitLength = 6
//options.TopOverCostCount = 2000
//options.BaseTime = time.Date(2020, 2, 20, 2, 20, 2, 20, time.UTC).UnixNano() / 1e6
yid.SetIdGenerator(options)
```
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package contract
type IIdGenerator interface {
NewLong() uint64
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package contract
type ISnowWorker interface {
NextId() uint64
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package contract
import "fmt"
type IdGeneratorException struct {
message string
error error
}
func (e IdGeneratorException) IdGeneratorException(message ...interface{}) {
fmt.Println(message)
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package contract
type IdGeneratorOptions struct {
Method uint16 // 雪花计算方法,(1-漂移算法|2-传统算法),默认1
BaseTime int64 // 基础时间(ms单位),不能超过当前系统时间
WorkerId uint16 // 机器码,与 WorkerIdBitLength 有关系
WorkerIdBitLength byte // 机器码位长,范围:1-21(要求:序列数位长+机器码位长不超过22)
SeqBitLength byte // 序列数位长,范围:2-21(要求:序列数位长+机器码位长不超过22)
MaxSeqNumber uint32 // 最大序列数(含),(由SeqBitLength计算的最大值)
MinSeqNumber uint32 // 最小序列数(含),默认5,不小于1,不大于MaxSeqNumber
TopOverCostCount uint32 // 最大漂移次数(含),默认2000,推荐范围500-10000(与计算能力有关)
}
func NewIdGeneratorOptions(workerId uint16) *IdGeneratorOptions {
return &IdGeneratorOptions{
Method: 1,
WorkerId: workerId,
BaseTime: 1582136402000,
WorkerIdBitLength: 6,
SeqBitLength: 6,
MaxSeqNumber: 0,
MinSeqNumber: 5,
TopOverCostCount: 2000,
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package contract
type OverCostActionArg struct {
ActionType int32
TimeTick int64
WorkerId uint16
OverCostCountInOneTerm int32
GenCountInOneTerm int32
TermIndex int32
}
func (ocaa OverCostActionArg) OverCostActionArg(workerId uint16, timeTick int64, actionType int32, overCostCountInOneTerm int32, genCountWhenOverCost int32, index int32) {
ocaa.ActionType = actionType
ocaa.TimeTick = timeTick
ocaa.WorkerId = workerId
ocaa.OverCostCountInOneTerm = overCostCountInOneTerm
ocaa.GenCountInOneTerm = genCountWhenOverCost
ocaa.TermIndex = index
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package core
import (
"sync"
"time"
"yitidgen/contract"
)
type SnowWorkerM1 struct {
BaseTime int64 //基础时间
WorkerId uint16 //机器码
WorkerIdBitLength byte //机器码位长
SeqBitLength byte //自增序列数位长
MaxSeqNumber uint32 //最大序列数(含)
MinSeqNumber uint32 //最小序列数(含)
TopOverCostCount uint32 //最大漂移次数
_TimestampShift byte
_CurrentSeqNumber uint32
_LastTimeTick int64
_TurnBackTimeTick int64
_TurnBackIndex byte
_IsOverCost bool
_OverCostCountInOneTerm uint32
_GenCountInOneTerm uint32
_TermIndex uint32
sync.Mutex
}
func NewSnowWorkerM1(options *contract.IdGeneratorOptions) contract.ISnowWorker {
var workerIdBitLength byte
var seqBitLength byte
var maxSeqNumber uint32
var workerId = options.WorkerId
if options.WorkerIdBitLength == 0 {
workerIdBitLength = 6
} else {
workerIdBitLength = options.WorkerIdBitLength
}
if options.SeqBitLength == 0 {
seqBitLength = 6
} else {
seqBitLength = options.SeqBitLength
}
if options.MaxSeqNumber > 0 {
maxSeqNumber = options.MaxSeqNumber
} else {
maxSeqNumber = (1 << seqBitLength) - 1
}
var minSeqNumber = options.MinSeqNumber
var topOverCostCount = options.TopOverCostCount
var baseTime int64
if options.BaseTime != 0 {
baseTime = options.BaseTime
} else {
baseTime = 1582136402000
}
timestampShift := (byte)(options.WorkerIdBitLength + options.SeqBitLength)
currentSeqNumber := options.MinSeqNumber
return &SnowWorkerM1{
BaseTime: baseTime,
WorkerId: workerId,
WorkerIdBitLength: workerIdBitLength,
SeqBitLength: seqBitLength,
MaxSeqNumber: maxSeqNumber,
MinSeqNumber: minSeqNumber,
TopOverCostCount: topOverCostCount,
_TimestampShift: timestampShift,
_CurrentSeqNumber: currentSeqNumber}
}
func (m1 *SnowWorkerM1) DoGenIdAction(arg *contract.OverCostActionArg) {
}
func (m1 *SnowWorkerM1) BeginOverCostAction(useTimeTick int64) {
}
func (m1 *SnowWorkerM1) EndOverCostAction(useTimeTick int64) {
if m1._TermIndex > 10000 {
m1._TermIndex = 0
}
}
func (m1 *SnowWorkerM1) BeginTurnBackAction(useTimeTick int64) {
}
func (m1 *SnowWorkerM1) EndTurnBackAction(useTimeTick int64) {
}
func (m1 *SnowWorkerM1) NextOverCostId() uint64 {
currentTimeTick := m1.GetCurrentTimeTick()
if currentTimeTick > m1._LastTimeTick {
m1.EndOverCostAction(currentTimeTick)
m1._LastTimeTick = currentTimeTick
m1._CurrentSeqNumber = m1.MinSeqNumber
m1._IsOverCost = false
m1._OverCostCountInOneTerm = 0
m1._GenCountInOneTerm = 0
return m1.CalcId(m1._LastTimeTick)
}
if m1._OverCostCountInOneTerm >= m1.TopOverCostCount {
m1.EndOverCostAction(currentTimeTick)
m1._LastTimeTick = m1.GetNextTimeTick()
m1._CurrentSeqNumber = m1.MinSeqNumber
m1._IsOverCost = false
m1._OverCostCountInOneTerm = 0
m1._GenCountInOneTerm = 0
return m1.CalcId(m1._LastTimeTick)
}
if m1._CurrentSeqNumber > m1.MaxSeqNumber {
m1._LastTimeTick++
m1._CurrentSeqNumber = m1.MinSeqNumber
m1._IsOverCost = true
m1._OverCostCountInOneTerm++
m1._GenCountInOneTerm++
return m1.CalcId(m1._LastTimeTick)
}
m1._GenCountInOneTerm++
return m1.CalcId(m1._LastTimeTick)
}
func (m1 *SnowWorkerM1) NextNormalId() uint64 {
currentTimeTick := m1.GetCurrentTimeTick()
if currentTimeTick < m1._LastTimeTick {
if m1._TurnBackTimeTick < 1 {
m1._TurnBackTimeTick = m1._LastTimeTick - 1
m1._TurnBackIndex++
// 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序
// 最多4次回拨(防止回拨重叠)
if m1._TurnBackIndex > 4 {
m1._TurnBackIndex = 1
}
m1.BeginTurnBackAction(m1._TurnBackTimeTick)
}
time.Sleep(time.Duration(10) * time.Millisecond)
return m1.CalcTurnBackId(m1._TurnBackTimeTick)
}
// 时间追平时,_TurnBackTimeTick清零
if m1._TurnBackTimeTick > 0 {
m1.EndTurnBackAction(m1._TurnBackTimeTick)
m1._TurnBackTimeTick = 0
}
if currentTimeTick > m1._LastTimeTick {
m1._LastTimeTick = currentTimeTick
m1._CurrentSeqNumber = m1.MinSeqNumber
return m1.CalcId(m1._LastTimeTick)
}
if m1._CurrentSeqNumber > m1.MaxSeqNumber {
m1.BeginOverCostAction(currentTimeTick)
m1._TermIndex++
m1._LastTimeTick++
m1._CurrentSeqNumber = m1.MinSeqNumber
m1._IsOverCost = true
m1._OverCostCountInOneTerm = 1
m1._GenCountInOneTerm = 1
return m1.CalcId(m1._LastTimeTick)
}
return m1.CalcId(m1._LastTimeTick)
}
func (m1 *SnowWorkerM1) CalcId(useTimeTick int64) uint64 {
result := uint64(useTimeTick<<m1._TimestampShift) + uint64(m1.WorkerId<<m1.SeqBitLength) + uint64(m1._CurrentSeqNumber)
m1._CurrentSeqNumber++
return result
}
func (m1 *SnowWorkerM1) CalcTurnBackId(useTimeTick int64) uint64 {
result := uint64(useTimeTick<<m1._TimestampShift) + uint64(m1.WorkerId<<m1.SeqBitLength) + uint64(m1._TurnBackIndex)
m1._TurnBackTimeTick--
return result
}
func (m1 *SnowWorkerM1) GetCurrentTimeTick() int64 {
var millis = time.Now().UnixNano() / 1e6
return millis - m1.BaseTime
}
func (m1 *SnowWorkerM1) GetNextTimeTick() int64 {
tempTimeTicker := m1.GetCurrentTimeTick()
for tempTimeTicker <= m1._LastTimeTick {
tempTimeTicker = m1.GetCurrentTimeTick()
}
return tempTimeTicker
}
func (m1 *SnowWorkerM1) NextId() uint64 {
m1.Lock()
defer m1.Unlock()
if m1._IsOverCost {
return m1.NextOverCostId()
} else {
return m1.NextNormalId()
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package core
import (
"fmt"
"strconv"
"yitidgen/contract"
)
type SnowWorkerM2 struct {
*SnowWorkerM1
}
func NewSnowWorkerM2(options *contract.IdGeneratorOptions) contract.ISnowWorker {
return &SnowWorkerM2{
NewSnowWorkerM1(options).(*SnowWorkerM1),
}
}
func (m2 SnowWorkerM2) NextId() uint64 {
m2.Lock()
defer m2.Unlock()
currentTimeTick := m2.GetCurrentTimeTick()
if m2._LastTimeTick == currentTimeTick {
m2._CurrentSeqNumber++
if m2._CurrentSeqNumber > m2.MaxSeqNumber {
m2._CurrentSeqNumber = m2.MinSeqNumber
currentTimeTick = m2.GetNextTimeTick()
}
} else {
m2._CurrentSeqNumber = m2.MinSeqNumber
}
if currentTimeTick < m2._LastTimeTick {
fmt.Println("Time error for {0} milliseconds", strconv.FormatInt(m2._LastTimeTick-currentTimeTick, 10))
}
m2._LastTimeTick = currentTimeTick
result := uint64((currentTimeTick << m2._TimestampShift)) + uint64(m2.WorkerId<<m2.SeqBitLength) + uint64(m2._CurrentSeqNumber)
return result
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package gen
import (
"time"
"yitidgen/contract"
"yitidgen/core"
)
type DefaultIdGenerator struct {
Options *contract.IdGeneratorOptions
SnowWorker contract.ISnowWorker
IdGeneratorException contract.IdGeneratorException
}
func NewDefaultIdGenerator(options *contract.IdGeneratorOptions) *DefaultIdGenerator {
if options == nil {
panic("dig.Options error.")
}
minTime := int64(631123200000) // time.Now().AddDate(-30, 0, 0).UnixNano() / 1e6
if options.BaseTime < minTime || options.BaseTime > time.Now().UnixNano()/1e6 {
panic("BaseTime error.")
}
if options.SeqBitLength+options.WorkerIdBitLength > 22 {
panic("error:WorkerIdBitLength + SeqBitLength <= 22")
}
maxWorkerIdNumber := uint16(1<<options.WorkerIdBitLength) - 1
if options.WorkerId > maxWorkerIdNumber {
panic("WorkerId error. (range:[1, " + string(maxWorkerIdNumber) + "]")
}
if options.SeqBitLength < 2 || options.SeqBitLength > 21 {
panic("SeqBitLength error. (range:[2, 21])")
}
maxSeqNumber := uint32(1<<options.SeqBitLength) - 1
if options.MaxSeqNumber > maxSeqNumber {
panic("MaxSeqNumber error. (range:[1, " + string(maxSeqNumber) + "]")
}
if options.MinSeqNumber > maxSeqNumber {
panic("MinSeqNumber error. (range:[1, " + string(maxSeqNumber) + "]")
}
var snowWorker contract.ISnowWorker
switch options.Method {
case 1:
snowWorker = core.NewSnowWorkerM1(options)
case 2:
snowWorker = core.NewSnowWorkerM2(options)
default:
snowWorker = core.NewSnowWorkerM1(options)
}
if options.Method == 1 {
time.Sleep(time.Duration(500) * time.Microsecond)
}
return &DefaultIdGenerator{
Options: options,
SnowWorker: snowWorker,
}
}
func (dig DefaultIdGenerator) NewLong() uint64 {
return dig.SnowWorker.NextId()
}
/*
* 版权属于:yitter(yitter@126.com)
* 代码编辑:guoyahao
* 代码修订:yitter
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package gen
import (
"sync"
"yitidgen/contract"
)
var ins *YitIdHelper
var once sync.Once
type YitIdHelper struct {
idGenInstance interface {
NewLong() uint64
}
}
func GetIns() *YitIdHelper {
once.Do(func() {
ins = &YitIdHelper{}
})
return ins
}
func (yih *YitIdHelper) GetIdGenInstance() interface{} {
return yih.idGenInstance
}
func (yih *YitIdHelper) SetIdGenerator(options *contract.IdGeneratorOptions) {
yih.idGenInstance = NewDefaultIdGenerator(options)
}
func (yih *YitIdHelper) NextId() uint64 {
once.Do(func() {
if yih.idGenInstance == nil {
options := contract.NewIdGeneratorOptions(1)
yih.idGenInstance = NewDefaultIdGenerator(options)
}
})
return yih.idGenInstance.NewLong()
}
module "yitidgen"
\ No newline at end of file
package main
import (
"fmt"
"time"
"yitidgen/contract"
"yitidgen/gen"
)
func main() {
// 方法一:直接采用默认方法生成一个Id
var yid = gen.YitIdHelper{}
fmt.Println(yid.NextId())
// 方法二:自定义参数
var options = contract.NewIdGeneratorOptions(1)
//options.WorkerIdBitLength = 6
//options.SeqBitLength = 6
//options.TopOverCostCount = 2000
//options.BaseTime = time.Date(2020, 2, 20, 2, 20, 2, 20, time.UTC).UnixNano() / 1e6
yid.SetIdGenerator(options)
var times = 50000
for {
var begin = time.Now().UnixNano() / 1e6
for i := 0; i < times; i++ {
yid.NextId()
}
var end = time.Now().UnixNano() / 1e6
fmt.Println(end - begin)
time.Sleep(time.Duration(1000) * time.Millisecond)
}
}
## 运行环境
JDK 1.8+
## 引用 maven 包
```
```
## 调用示例
```
// 全局初始化设置WorkerId,默认最大2^16-1。(初始化过程全局只需一次,且必须最先设置)
IdGeneratorOptions options = new IdGeneratorOptions();
options.WorkerId = 1;
YitIdHelper.setIdGenerator(options);
// 初始化以后,就可以在需要的地方调用方法生成ID。
long newId = YitIdHelper.nextId();
```
如果基于DI框架集成,可以参考 YitIdHelper 去管理 IdGenerator 对象,必须使用**单例**模式。
## options 默认值及说明
参考源码:/contract/IdGeneratorOptions.java
# Compiled class file
*.class
*.iml
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
target/
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yitter</groupId>
<artifactId>yitter.idgenerator</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>yitter.idgenerator</name>
<description>Shorter ID and faster generation with a new snowflake drift algorithm. The core is to shorten the ID length, but also can have a very high instantaneous concurrent processing capacity (50W/0.1s), and powerful configuration capacity.</description>
<developers>
<developer>
<id>yitter</id>
<name>yitter</name>
<email>yitter@126.com</email>
<url>https://gitee.com/yitter/idgenerator</url>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<resources>
<resource>
<directory>${project.basedir}</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>LICENSE</include>
<include>NOTICE</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**</include>
</includes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<includes>
<include>**</include>
</includes>
</testResource>
</testResources>
</build>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
</project>
\ No newline at end of file
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.contract;
public interface IIdGenerator {
long newLong() throws IdGeneratorException;
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.contract;
public interface ISnowWorker {
long nextId() throws IdGeneratorException;
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.contract;
public class IdGeneratorException extends RuntimeException {
public IdGeneratorException() {
super();
}
public IdGeneratorException(String message) {
super(message);
}
public IdGeneratorException(Throwable cause) {
super(cause);
}
public IdGeneratorException(String message, Throwable cause) {
super(message, cause);
}
public IdGeneratorException(String msgFormat, Object... args) {
super(String.format(msgFormat, args));
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.contract;
/**
* 雪花算法使用的参数
* 此处代码不采用 get/set 那种冗长的写法
*/
public class IdGeneratorOptions {
/**
* 雪花计算方法
* (1-漂移算法|2-传统算法),默认1
*/
public short Method = 1;
/**
* 基础时间(ms单位)
* 不能超过当前系统时间
*/
public long BaseTime = 1582136402000L;
/**
* 机器码,必须由外部系统设置
* 与 WorkerIdBitLength 有关系
* (short类型,最大值32766,如果有更高要求,请修改数据类型,或联系作者)
*/
public short WorkerId = 0;
/**
* 机器码位长
* 范围:1-21(要求:序列数位长+机器码位长不超过22)。
* 建议范围:6-12。
*/
public byte WorkerIdBitLength = 6;
/**
* 序列数位长
* 范围:2-21(要求:序列数位长+机器码位长不超过22)。
* 建议范围:6-14。
*/
public byte SeqBitLength = 6;
/**
* 最大序列数(含)
* (由SeqBitLength计算的最大值)
*/
public short MaxSeqNumber = 0;
/**
* 最小序列数(含)
* 默认5,不小于1,不大于MaxSeqNumber
*/
public short MinSeqNumber = 5;
/**
* 最大漂移次数(含)
* 默认2000,推荐范围500-10000(与计算能力有关)
*/
public short TopOverCostCount = 2000;
public IdGeneratorOptions() {
}
public IdGeneratorOptions(short workerId) {
WorkerId = workerId;
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.contract;
/**
* Id生成时回调参数
*/
public class OverCostActionArg {
/**
* 事件类型
* 1-开始,2-结束,8-漂移
*/
public int ActionType = 0;
/**
* 时间戳
*/
public long TimeTick = 0;
/**
* 机器码
*/
public short WorkerId = 0;
/**
*
*/
public int OverCostCountInOneTerm = 0;
/**
* 漂移期间生产ID个数
*/
public int GenCountInOneTerm = 0;
/**
* 漂移周期
*/
public int TermIndex = 0;
public OverCostActionArg(short workerId, long timeTick, int actionType, int overCostCountInOneTerm, int genCountWhenOverCost, int index) {
ActionType = actionType;
TimeTick = timeTick;
WorkerId = workerId;
OverCostCountInOneTerm = overCostCountInOneTerm;
GenCountInOneTerm = genCountWhenOverCost;
TermIndex = index;
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.core;
import com.yitter.contract.ISnowWorker;
import com.yitter.contract.IdGeneratorException;
import com.yitter.contract.IdGeneratorOptions;
import com.yitter.contract.OverCostActionArg;
public class SnowWorkerM1 implements ISnowWorker {
/**
* 基础时间
*/
protected final long BaseTime;
/**
* 机器码
*/
protected final short WorkerId;
/**
* 机器码位长
*/
protected final byte WorkerIdBitLength;
/**
* 自增序列数位长
*/
protected final byte SeqBitLength;
/**
* 最大序列数(含)
*/
protected final int MaxSeqNumber;
/**
* 最小序列数(含)
*/
protected final short MinSeqNumber;
/**
* 最大漂移次数
*/
protected final int TopOverCostCount;
protected final byte _TimestampShift;
protected final static byte[] _SyncLock = new byte[0];
protected short _CurrentSeqNumber;
protected long _LastTimeTick = -1L;
protected long _TurnBackTimeTick = -1L;
protected byte _TurnBackIndex = 0;
protected boolean _IsOverCost = false;
protected int _OverCostCountInOneTerm = 0;
protected int _GenCountInOneTerm = 0;
protected int _TermIndex = 0;
public SnowWorkerM1(IdGeneratorOptions options) {
WorkerId = options.WorkerId;
WorkerIdBitLength = options.WorkerIdBitLength == 0 ? 6 : options.WorkerIdBitLength;
SeqBitLength = options.SeqBitLength == 0 ? 6 : options.SeqBitLength;
MaxSeqNumber = options.MaxSeqNumber > 0 ? options.MaxSeqNumber : (int) Math.pow(2, SeqBitLength) - 1;
MinSeqNumber = options.MinSeqNumber;
TopOverCostCount = options.TopOverCostCount;
BaseTime = options.BaseTime != 0 ? options.BaseTime : 1582136402000L;
_TimestampShift = (byte) (WorkerIdBitLength + SeqBitLength);
_CurrentSeqNumber = options.MinSeqNumber;
}
private void DoGenIdAction(OverCostActionArg arg) {
}
private void BeginOverCostAction(long useTimeTick) {
// if (GenAction == null) {
// return;
// }
//
// DoGenIdAction(new OverCostActionArg(
// WorkerId,
// useTimeTick,
// 1,
// _OverCostCountInOneTerm,
// _GenCountInOneTerm,
// _TermIndex));
}
private void EndOverCostAction(long useTimeTick) {
if (_TermIndex > 10000) {
_TermIndex = 0;
}
//
// if (GenAction == null) {
// return;
// }
//
// DoGenIdAction(new OverCostActionArg(
// WorkerId,
// useTimeTick,
// 2,
// _OverCostCountInOneTerm,
// _GenCountInOneTerm,
// _TermIndex));
}
private void BeginTurnBackAction(long useTimeTick) {
// if (GenAction == null) {
// return;
// }
//
// DoGenIdAction(new OverCostActionArg(
// WorkerId,
// useTimeTick,
// 8,
// _OverCostCountInOneTerm,
// _GenCountInOneTerm,
// _TermIndex));
}
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() throws IdGeneratorException {
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(10);
} 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) +
((long) WorkerId << SeqBitLength) +
(int) _CurrentSeqNumber);
_CurrentSeqNumber++;
return result;
}
private long CalcTurnBackId(long useTimeTick) {
long result = ((useTimeTick << _TimestampShift) +
((long) WorkerId << SeqBitLength) + _TurnBackIndex);
_TurnBackTimeTick--;
return result;
}
protected long GetCurrentTimeTick() {
long millis = System.currentTimeMillis();
return millis - BaseTime;
}
protected long GetNextTimeTick() {
long tempTimeTicker = GetCurrentTimeTick();
while (tempTimeTicker <= _LastTimeTick) {
tempTimeTicker = GetCurrentTimeTick();
}
return tempTimeTicker;
}
@Override
public long nextId() {
synchronized (_SyncLock) {
return _IsOverCost ? NextOverCostId() : NextNormalId();
}
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.core;
import com.yitter.contract.IdGeneratorException;
import com.yitter.contract.IdGeneratorOptions;
public class SnowWorkerM2 extends SnowWorkerM1 {
public SnowWorkerM2(IdGeneratorOptions options) {
super(options);
}
@Override
public long nextId() {
synchronized (_SyncLock) {
long currentTimeTick = GetCurrentTimeTick();
if (_LastTimeTick == currentTimeTick) {
if (_CurrentSeqNumber++ > MaxSeqNumber) {
_CurrentSeqNumber = MinSeqNumber;
currentTimeTick = GetNextTimeTick();
}
} else {
_CurrentSeqNumber = MinSeqNumber;
}
if (currentTimeTick < _LastTimeTick) {
throw new IdGeneratorException("Time error for {0} milliseconds", _LastTimeTick - currentTimeTick);
}
_LastTimeTick = currentTimeTick;
long result = ((currentTimeTick << _TimestampShift) + ((long) WorkerId << SeqBitLength) + (int) _CurrentSeqNumber);
return result;
}
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.idgen;
import com.yitter.contract.ISnowWorker;
import com.yitter.contract.IdGeneratorException;
import com.yitter.contract.IdGeneratorOptions;
import com.yitter.contract.IIdGenerator;
import com.yitter.core.SnowWorkerM1;
import com.yitter.core.SnowWorkerM2;
public class DefaultIdGenerator implements IIdGenerator {
private static ISnowWorker _SnowWorker = null;
public DefaultIdGenerator(IdGeneratorOptions options) throws IdGeneratorException {
if (options == null) {
throw new IdGeneratorException("options error.");
}
if (options.BaseTime < 315504000000L || options.BaseTime > System.currentTimeMillis()) {
throw new IdGeneratorException("BaseTime error.");
}
if (options.WorkerIdBitLength <= 0) {
throw new IdGeneratorException("WorkerIdBitLength error.(range:[1, 21])");
}
if (options.SeqBitLength + options.WorkerIdBitLength > 22) {
throw new IdGeneratorException("error:WorkerIdBitLength + SeqBitLength <= 22");
}
int maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1;
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber) {
throw new IdGeneratorException("WorkerId error. (range:[0, " + (maxWorkerIdNumber > 0 ? maxWorkerIdNumber : 63) + "]");
}
if (options.SeqBitLength < 2 || options.SeqBitLength > 21) {
throw new IdGeneratorException("SeqBitLength error. (range:[2, 21])");
}
int maxSeqNumber = (1 << options.SeqBitLength) - 1;
if (options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber) {
throw new IdGeneratorException("MaxSeqNumber error. (range:[1, " + maxSeqNumber + "]");
}
int maxValue = maxSeqNumber;
if (options.MinSeqNumber < 1 || options.MinSeqNumber > maxValue) {
throw new IdGeneratorException("MinSeqNumber error. (range:[1, " + maxValue + "]");
}
switch (options.Method) {
case 1:
_SnowWorker = new SnowWorkerM1(options);
break;
case 2:
_SnowWorker = new SnowWorkerM2(options);
break;
default:
_SnowWorker = new SnowWorkerM1(options);
break;
}
if (options.Method == 1) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public long newLong() {
return _SnowWorker.nextId();
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
package com.yitter.idgen;
import com.yitter.contract.IdGeneratorException;
import com.yitter.contract.IdGeneratorOptions;
import com.yitter.contract.IIdGenerator;
/**
* 这是一个调用的例子,默认情况下,单机集成者可以直接使用 nextId()。
*/
public class YitIdHelper {
private static IIdGenerator idGenInstance = null;
public static IIdGenerator getIdGenInstance() {
return idGenInstance;
}
/**
* 设置参数,建议程序初始化时执行一次
*
* @param options
*/
public static void setIdGenerator(IdGeneratorOptions options) throws IdGeneratorException {
idGenInstance = new DefaultIdGenerator(options);
}
/**
* 生成新的Id
* 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。
*
* @return
*/
public static long nextId() throws IdGeneratorException {
if (idGenInstance == null) {
idGenInstance = new DefaultIdGenerator(new IdGeneratorOptions((short) 1));
}
return idGenInstance.newLong();
}
}
package com.yitter.test;
import com.yitter.contract.IIdGenerator;
import java.util.HashSet;
import java.util.Set;
public class GenTest {
private IIdGenerator IdGen;
private int GenIdCount;
private int WorkerId;
private Set IdSet = new HashSet();
public GenTest(IIdGenerator idGen, int genIdCount, int workerId) {
GenIdCount = genIdCount;
IdGen = idGen;
WorkerId = workerId;
}
public void GenStart() {
long start = System.currentTimeMillis();
long id = 0;
for (int i = 0; i < GenIdCount; i++) {
id = IdGen.newLong();
// IdSet.add(id);
}
long end = System.currentTimeMillis();
long time = end - start;
System.out.println(id);
System.out.println("++++++++++++++++++++++++++++++++++++++++WorkerId: "
+ WorkerId + ", total: " + time + " ms");
}
}
package com.yitter.test;
import com.yitter.contract.IdGeneratorOptions;
import com.yitter.contract.IIdGenerator;
import com.yitter.idgen.DefaultIdGenerator;
import com.yitter.idgen.YitIdHelper;
public class StartUp {
/**
* 测试结果:
* (1):1W并发,方法 1只要 1ms.而方法 2 要 180ms。
* (2):5W并发,方法 1只要 3ms.而方法 2 要 900ms。
* [不同CPU可能结果有差异,但相对大小不变]
* 默认配置下,最佳性能是5W/s-8W/s
*/
final static int genIdCount = 50000;
//1-漂移算法,2-传统算法
final static short method = 1;
public static void main(String[] args) {
IdGeneratorOptions options = new IdGeneratorOptions();
// options.WorkerIdBitLength = 6;
// options.SeqBitLength = 6;
// options.TopOverCostCount = 2000;
// options.MinSeqNumber = 5;
// options.MaxSeqNumber = 200;
options.Method = method;
options.BaseTime = 1582206693000L;
options.WorkerId = 1;
IIdGenerator idGen = new DefaultIdGenerator(options);
GenTest genTest = new GenTest(idGen, genIdCount, options.WorkerId);
// 首先测试一下 IdHelper 方法,获取单个Id
YitIdHelper.setIdGenerator(options);
long newId = YitIdHelper.nextId();
System.out.println("=====================================");
System.out.println("这是用方法 " + method + " 生成的 Id:" + newId);
// 然后循环测试一下,看看并发请求时的耗时情况
try {
while (true) {
genTest.GenStart();
Thread.sleep(1000); // 每隔1秒执行一次GenStart
System.out.println("Hello World! Java");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
# idgenerator
something is going on.
# idgenerator
#### Description
用一种全新的雪花漂移算法,让ID更短、生成速度更快,0.1秒可生成50万个ID。
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
# IdGenerator SnowFlake 雪花算法 原生多语言版本 顶尖优化 超强效能
## 介绍
1.一个全新的雪花漂移算法,使生成的ID更短、速度更快。
2.核心在于缩短ID长度的同时,还能拥有极高瞬时并发处理量(保守值 50W/0.1s)。
3.原生支持 C#/Java/Go/Rust/C 等语言,并由 Rust 提供 PHP、Python、Node.js、Ruby 等语言多线程安全调用库(FFI)。
## 技术支持
开源地址:https://gitee.com/yitter/idgenerator
QQ群:646049993
## 需求来源
1.作为架构设计的你,想要解决数据库主键唯一的问题,特别是在分布式系统多数据库的时候。
2.你希望这个主键是用最少的存储空间,索引速度更快,Select、Insert 和 Update 更迅速。
3.你要考虑在分库分表(合库合表)时,主键值可直接使用,并能反映业务时序。
4.如果这样的主键值太长,超过前端 JS Number 类型最大值,须把 Long 型转换为 String 型,你会觉得有点沮丧。
5.哪怕 Guid 能自增,但占用空间大,索引速度慢,所以你也不想用它。
6.你的应用实例可能超过50个,每个并发请求可达10W/s。
7.在容器环境部署应用(水平扩展、自动伸缩)。
8.你可不想 Id 生成器依赖 redis 的自增操作。
9.你希望系统运行 100 年以上。
## 传统算法问题
1.生成的ID太长。
2.瞬时并发量不够。
3.不能解决时间回拨问题。
4.不支持后补生成前序ID。
5.依赖外部存储系统。
## 新算法特点
1.整形数字,随时间单调递增(不一定连续),长度更短,用50年都不会超过 js Number类型最大值。(默认配置 WorkerId 是6bit,自增数是6bit)
2.速度更快,是传统雪花算法的2-5倍,0.1秒可生成50万个。(i7笔记本,默认算法配置6bit+6bit)
3.支持时间回拨处理。比如服务器时间回拨1秒,本算法能自动适应生成临界时间的唯一ID。
4.支持手工插入新ID。当业务需要在历史时间生成新ID时,用本算法的预留位能生成5000个每秒。
5.漂移时能外发通知事件。让调用方确切知道算法漂移记录,Log并发调用量。
6.不依赖任何外部缓存和数据库。(当然 WorkerId 须由外部指定)
## 性能数据
(参数:10位自增序列,1000次漂移最大值)
| 连续请求量 | 5K | 5W | 50W |
| ---- | ---- | ---- | ---- |
| 传统雪花算法 | 0.0045s | 0.053s | 0.556s |
| 雪花漂移算法 | 0.0015s | 0.012s | 0.113s |
## 效果
1.js Number 类型最大数值:9007199254740992,本算法在保持并发性能(5W+/0.01s)和最大64个 WorkerId(6bit)的同时,能用70年才到 js Number Max 值。
2.增加WorkerId位数到8bit(256节点)时,15年达到 js Number Max 值。
3.极致性能:500W/s~3000W/s。
4.所有测试数据均基于8代低压i7计算。
#### 生成的ID
默认配置:
```
WorkerIdBitLength = 6
SeqBitLength = 6
```
ID示例(基于默认配置):
```
129053495681099 (本算法运行1年)
387750301904971 (运行3年)
646093214093387 (运行5年)
1292658282840139 (运行10年)
9007199254740992 (js Number 最大值)
165399880288699493 (普通雪花算法生成的ID)
```
本算法生成的 ID 值,是 js Number 最大值的 1%-10%,是普通雪花算法值的千分之一,而计算能力却超过普通雪花算法。
## 适用范围
1.小型、中型、大型需要全局唯一Id(不用Guid)的项目。
2.分布式项目。
3.不想将 Long 型转 String 给前端用的项目。(若前端支持bigint,则可不转类型)
## 如何处理时间回拨
1.当发生系统时间回拨时,算法采用过去时序的预留序数生成新的ID。
2.默认每秒生成100个(速度可调整)。
3.回拨生成的ID序号,默认靠前,也可以调整为靠后。
4.允许时间回拨至本算法预设基数(参数可调)。
## 能用多久
1.在默认配置下,ID可用 71000 年不重复。
2.在支持 1024 个工作节点时,ID可用 4480 年不重复。
3.在支持 4096 个工作节点时,ID可用 1120 年不重复。
4.以上所有工作节点,均拥有 50W/0.1s 瞬时处理速度。
#### 默认配置
1.WorkerIdBitLength=6,能支持64个 WorkerId,编号0~63。
2.可通过减少 WorkerIdBitLength 到1~4(为4时最大支持WorkerId为2^4=16个),以减少Id长度。
3.SeqBitLength=6,能支持每秒并发5W请求时,平均处理速度不超过 0.005 s。(不同语言略有差别,最高性能不超过0.002s,平均不超过0.005s)
4.可通过增加 SeqBitLength,支持更高的每秒并发数。默认配置能很高效地支持每秒 5W 并发请求,若要求更高,可适当增加 SeqBitLength 到 8~16,但这将增加Id长度。
## ★★集成建议★★
#### 常规集成
1.用单例模式调用。外部集成方使用更多的实例并行调用本算法,不会增加ID产出效能,因为本算法采用单线程模式生成ID。
2.指定唯一的 WorkerId。必须由外部系统确保 WorkerId 的全局唯一性,并赋值给本算法入口方法。
3.单机多实例部署时使用不同 WorkerId。并非所有实现都支持跨进程的并发唯一,保险起见,在同一主机上部署多应用实例时,请确保各 WorkerId 唯一。
4.异常处理。算法会抛出所有 Exception,外部系统应 catch 异常并做好应对处理,以免引发更大的系统崩溃。
5.认真理解 IdGeneratorOptions 的定义,这对集成和使用本算法有帮助。
6.使用雪花漂移算法。虽然代码里包含了传统雪花算法的定义,并且你可以在入口处指定(Method=2)来启用传统算法,但仍建议你使用雪花漂移算法(Method=1,默认的),毕竟它具有更好的伸缩力和更高的性能。
7.不要修改核心算法。本算法内部参数较多,逻辑较为复杂,在你尚未掌握核心逻辑时,请勿尝试修改核心代码且用于生产环境,除非通过大量细致、科学的测试验证。
#### 大型分布式集成
1.可增加 WorkerIdBitLength 到最大20,支持 1,048,576 个节点,且不影响上述并发性能。[算法支持]
2.采用中心化 IdGenerator 集群,生成可用 Id 列表,存入 Redis 队列供节点消费。此时64个中心化节点数足够大型互联网项目使用。[需集成方扩展实现]
3.以上2条二选一即可,采用方法2一般是因为不想增加最终 ID 长度,但节点数超过64个。
4.任何加大 WorkerIdBitLength 或 SeqBitLength 的设置,都可能会增加 ID 的长度。
#### 配置变更
配置变更指是系统运行一段时间后,再变更运行参数(IdGeneratorOptions选项值),请注意:
1.最重要的一条原则是:BaseTime **只能往前**(比老值更小、距离现在更远)赋值,原因是往后赋值极大可能产生相同的时间戳。[**不推荐**在系统运行之后调整 BaseTime]
2.任何时候增加 WorkerIdBitLength 或 SeqBitLength,都是可以的,但是慎用 “减小”的操作,因为这可能导致在未来某天生成的 ID 与过去老配置时相同。[允许在系统运行之后**增加**任何一个 BitLength 值]
3.如果必须减小 WorkerIdBitLength 或 SeqBitLength 其中的一项,一定要满足一个条件:新的两个 BitLength 之和要大于 老的值之和。[**不推荐**在运行之后缩小任何一个 BitLength 值]
4.上述3条规则,并未在本算法内做逻辑控制,集成方应根据上述规则做好影响评估,确认无误后,再实施配置变更。
## 代码示例
C#:[查看示例][1]
Java:[查看示例][2]
Go:[查看示例][3]
Rust:[查看示例][4]
即将推出 PHP 扩展调用版本。
[1]: https://gitee.com/yitter/idgenerator/tree/master/C%23.NET
[2]: https://gitee.com/yitter/idgenerator/tree/master/Java
[3]: https://gitee.com/yitter/idgenerator/tree/master/Go
[4]: https://gitee.com/yitter/idgenerator/tree/master/Rust
# idgenerator
Done.
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
*.editorconfig
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
**/.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
*.snupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
target/
# macOS
.DS_Store
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae"
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yitidgen"
version = "1.0.0"
dependencies = [
"chrono",
"lazy_static",
]
[package]
name = "yitidgen"
version = "1.0.0"
authors = ["yitter <yitter@126.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = "0.4.10"
lazy_static = "1.4.0"
[lib]
name = "yitidgen"
path = "./src/lib.rs"
crate-type = ["cdylib"]
mod yitgen;
use yitgen::gen::YitIdHelper;
use yitgen::contract::*;
// #[export_name = "SetIdGenerator"]
#[no_mangle]
pub extern "C" fn SetIdGenerator(options: IdGeneratorOptions) {
YitIdHelper::SetIdGenerator(options);
}
#[no_mangle]
pub extern "C" fn SetWorkerId(workerId: u32) {
YitIdHelper::SetWorkerId(workerId);
}
#[no_mangle]
pub extern "C" fn NextId() -> i64 {
YitIdHelper::NextId()
}
mod yitgen;
use yitgen::contract::*;
use yitgen::gen::*;
use std::thread;
use chrono::Utc;
use std::time::Duration;
fn main() {
println!("Hello, world! Rust");
// 总执行次数
let times = 50000;
// 是否启用多线程测试
let multiThread = false;
// 全局设置一次运行参数
let mut options = IdGeneratorOptions::New(1);
options.WorkerIdBitLength = 6;
options.SeqBitLength = 6;
//... 可以继续设置其它 options 参数
YitIdHelper::SetIdGenerator(options);
// 以下开始测试生成数据,默认5W,单线程,可以修改 multiThread=true 启用多线程。
loop {
let mut i = 0;
let mut id: i64 = 0;
let start = Utc::now().timestamp_millis();
while i < times {
i += 1;
if multiThread { // 这是多线程
thread::spawn(move || {
id = YitIdHelper::NextId();
println!("{}, id: {}", i, id);
});
} else { // 这是单线程
id = YitIdHelper::NextId();
}
}
println!("最后生成的id: {}", id);
if !multiThread {
// 多线程情况下,时间统计不准确
let end = Utc::now().timestamp_millis();
println!("单线程用时 {} ms", end - start);
}
thread::sleep(std::time::Duration::from_millis(2000));
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
pub trait ISnowWorker {
fn NextId(&self) -> u64;
}
\ No newline at end of file
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
pub struct IdGeneratorOptions {
/// 雪花计算方法,(1-漂移算法|2-传统算法),默认1
pub Method: u8,
/// 基础时间(ms单位),不能超过当前系统时间
pub BaseTime: i64,
/// 机器码,与 WorkerIdBitLength 有关系
pub WorkerId: u32,
/// 机器码位长,范围:1-21(要求:序列数位长+机器码位长不超过22)
pub WorkerIdBitLength: u8,
/// 序列数位长,范围:2-21(要求:序列数位长+机器码位长不超过22)
pub SeqBitLength: u8,
/// 最大序列数(含),(由 SeqBitLength 计算的最大值)
pub MaxSeqNumber: u32,
/// 最小序列数(含),默认5,不小于5,不大于 MaxSeqNumber
pub MinSeqNumber: u32,
/// 最大漂移次数(含),默认2000,推荐范围 500-20000(与计算能力有关)
pub TopOverCostCount: u32,
}
impl IdGeneratorOptions {
pub fn New(workerId: u32) -> IdGeneratorOptions {
return IdGeneratorOptions {
Method: 1,
WorkerId: workerId,
BaseTime: 1582136402000,
WorkerIdBitLength: 6,
SeqBitLength: 6,
MaxSeqNumber: 0,
MinSeqNumber: 5,
TopOverCostCount: 2000,
};
}
}
\ No newline at end of file
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
mod id_generator_options;
mod i_snow_worker;
mod over_cost_action_arg;
pub use id_generator_options::IdGeneratorOptions;
pub use i_snow_worker::ISnowWorker;
pub use over_cost_action_arg::OverCostActionArg;
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
pub struct OverCostActionArg {
ActionType: u32,
TimeTick: u64,
WorkerId: u16,
OverCostCountInOneTerm: u32,
GenCountInOneTerm: u32,
TermIndex: u32,
}
\ No newline at end of file
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
mod snow_worker_m1;
mod snow_worker_m2;
pub use snow_worker_m1::SnowWorkerM1;
pub use snow_worker_m2::SnowWorkerM2;
此差异已折叠。
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
use super::super::contract::ISnowWorker;
pub struct SnowWorkerM2 {
}
\ No newline at end of file
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
use std::{thread, time};
use std::net::UdpSocket;
use chrono::Utc;
use super::super::contract::*;
use super::super::core::*;
use super::*;
use std::sync::Mutex;
use std::sync::Arc;
use std::borrow::BorrowMut;
static mut instance2: Option<Arc<Mutex<SnowWorkerM1>>> = None;
pub struct DefaultIdGenerator {
pub Worker: SnowWorkerM1,
}
impl DefaultIdGenerator {
pub fn Default() -> DefaultIdGenerator {
DefaultIdGenerator { Worker: SnowWorkerM1::Default() }
}
}
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
mod default_id_generator;
mod yit_id_helper;
pub use yit_id_helper::YitIdHelper;
pub use default_id_generator::DefaultIdGenerator;
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
use super::super::contract::*;
use super::super::core::*;
use super::*;
use std::sync::Mutex;
use std::sync::Arc;
pub struct YitIdHelper;
static mut idGenInstance: Option<Arc<Mutex<DefaultIdGenerator>>> = None;
impl YitIdHelper {
fn IdGenInstance() -> Arc<Mutex<DefaultIdGenerator>> {
unsafe {
idGenInstance.get_or_insert_with(|| {
Arc::new(Mutex::new(DefaultIdGenerator::Default()))
}).clone()
}
}
pub fn SetIdGenerator(options: IdGeneratorOptions) {
let mut idgenArc = YitIdHelper::IdGenInstance();
let mut idgen = idgenArc.lock().unwrap();
idgen.Worker.SetOptions(options);
}
pub fn SetWorkerId(workerId: u32) {
let mut idgenArc = YitIdHelper::IdGenInstance();
let mut idgen = idgenArc.lock().unwrap();
let mut options = IdGeneratorOptions::New(workerId);
idgen.Worker.SetOptions(options);
}
pub fn NextId() -> i64 {
let mut idgenArc = YitIdHelper::IdGenInstance();
let mut idgen = idgenArc.lock().unwrap();
idgen.Worker.NextId()
}
}
pub mod contract;
pub mod core;
pub mod gen;
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册