C# 根据twitter的snowflake算法生成唯一ID

C# 版算法:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6
 7 namespace Demo
 8 {
 9
10         /// <summary>
11         /// 根据twitter的snowflake算法生成唯一ID
12         /// snowflake算法 64 位
13         /// 0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
14         /// 第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
15         /// 其中datacenter标识位起始是机器位,机器ID其实是线程标识,可以同一一个10位来表示不同机器
16         /// </summary>
17         public class IdWorker
18         {
19             //机器ID
20             private static long workerId = 1;
21             private static long twepoch = 687888001020L; //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳
22             private static long sequence = 0L;
23             private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码
24             public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID
25             private static int sequenceBits = 10; //计数器字节数,10个字节用来保存计数码
26             private static int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
27             private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数
28             public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
29             private long lastTimestamp = -1L;
30
31             public long nextId()
32             {
33                 lock (this)
34                 {
35                     long timestamp = timeGen();
36                     if (this.lastTimestamp == timestamp)
37                     { //同一微妙中生成ID
38                         IdWorker.sequence = (IdWorker.sequence + 1) & IdWorker.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
39                         if (IdWorker.sequence == 0)
40                         {
41                             //一微妙内产生的ID计数已达上限,等待下一微妙
42                             timestamp = tillNextMillis(this.lastTimestamp);
43                         }
44                     }
45                     else
46                     { //不同微秒生成ID
47                         IdWorker.sequence = 0; //计数清0
48                     }
49                     if (timestamp < lastTimestamp)
50                     { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
51                         throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds",
52                             this.lastTimestamp - timestamp));
53                     }
54                     this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
55                     long nextId = (timestamp - twepoch << timestampLeftShift) | IdWorker.workerId << IdWorker.workerIdShift | IdWorker.sequence;
56                     return nextId;
57                 }
58             }
59
60             /// <summary>
61             /// 获取下一微秒时间戳
62             /// </summary>
63             /// <param name="lastTimestamp"></param>
64             /// <returns></returns>
65             private long tillNextMillis(long lastTimestamp)
66             {
67                 long timestamp = timeGen();
68                 while (timestamp <= lastTimestamp)
69                 {
70                     timestamp = timeGen();
71                 }
72                 return timestamp;
73             }
74
75             /// <summary>
76             /// 生成当前时间戳
77             /// </summary>
78             /// <returns></returns>
79             private long timeGen()
80             {
81                 return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
82             }
83         }
84     }

Java 版算法:

 1 import org.slf4j.Logger;
 2 import org.slf4j.LoggerFactory;
 3 import org.springframework.stereotype.Component;
 4
 5 public class IdWorker {
 6
 7     protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);
 8
 9     private long workerId;
10     private long datacenterId;
11     private long sequence = 0L;
12
13     private long twepoch = 1288834974657L;
14
15     private long workerIdBits = 5L;
16     private long datacenterIdBits = 5L;
17     private long maxWorkerId = -1L ^ (-1L << workerIdBits);
18     private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
19     private long sequenceBits = 12L;
20
21     private long workerIdShift = sequenceBits;
22     private long datacenterIdShift = sequenceBits + workerIdBits;
23     private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
24     private long sequenceMask = -1L ^ (-1L << sequenceBits);
25
26     private long lastTimestamp = -1L;
27
28     public IdWorker(long workerId, long datacenterId) {
29         // sanity check for workerId
30         if (workerId > maxWorkerId || workerId < 0) {
31             throw new IllegalArgumentException(String.format("worker Id can‘t be greater than %d or less than 0", maxWorkerId));
32         }
33         if (datacenterId > maxDatacenterId || datacenterId < 0) {
34             throw new IllegalArgumentException(String.format("datacenter Id can‘t be greater than %d or less than 0", maxDatacenterId));
35         }
36         this.workerId = workerId;
37         this.datacenterId = datacenterId;
38         LOG.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));
39     }
40
41     public synchronized long nextId() {
42         long timestamp = timeGen();
43
44         if (timestamp < lastTimestamp) {
45             LOG.error(String.format("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp));
46             throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
47         }
48
49         if (lastTimestamp == timestamp) {
50             sequence = (sequence + 1) & sequenceMask;
51             if (sequence == 0) {
52                 timestamp = tilNextMillis(lastTimestamp);
53             }
54         } else {
55             sequence = 0L;
56         }
57
58         lastTimestamp = timestamp;
59
60         return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
61     }
62
63     protected long tilNextMillis(long lastTimestamp) {
64         long timestamp = timeGen();
65         while (timestamp <= lastTimestamp) {
66             timestamp = timeGen();
67         }
68         return timestamp;
69     }
70
71     protected long timeGen() {
72         return System.currentTimeMillis();
73     }
74
75
76 }

留个脚印,备用!

时间: 2024-10-10 08:16:25

C# 根据twitter的snowflake算法生成唯一ID的相关文章

使用SnowFlake算法生成唯一ID

转自:https://segmentfault.com/a/1190000007769660 考虑过的方法有 直接用时间戳,或者以此衍生的一系列方法 Mysql自带的uuid 以上两种方法都可以查到就不多做解释了 最终选择了Twitter的SnowFlake算法 这个算法的好处很简单可以在每秒产生约400W个不同的16位数字ID(10进制) 原理很简单 ID由64bit组成 其中 第一个bit空缺 41bit用于存放毫秒级时间戳 10bit用于存放机器id 12bit用于存放自增ID 除了最高位

twitter的snowflake算法(C#版本)

转自:http://blog.csdn.net/kinwyb/article/details/50238505 使用twitter的snowflake算法生成唯一ID. 在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位+机器ID 10位+毫秒内序列12位. /// <summary> /// 根据twitter的snowflake算法生成唯一ID /// snowflake算法

在分布式场景,生成唯一ID

在分布式环境下生成数据库主键是一件比较麻烦的事情,这里简单总结下,以供以后使用. 数据库自增长序列或字段 每个服务器使用自增主键,不同服务器的步长不一样,比如 A 服务器生成 1,3,5,7... B 服务器生成 2,4,6,8.... 缺点:难以扩展.合并数据库时非常麻烦.分库分表时难以处理. UUID 常见的方式.可以利用数据库也可以利用程序生成,一般来说全球唯一. 缺点:没有排序,无法保证趋势递增.查询效率比较低.存储量比较大.不可读. Redis 生成 ID 使用 Redis 的原子性生

php 生成唯一id的几种解决方法

网上查了下,有很多的方法 1.md5(time() . mt_rand(1,1000000)); 这种方法有一定的概率会出现重复 2.php内置函数uniqid() uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID. w3school参考手册有一句话:"由于基于系统时间,通过该函数生成的 ID 不是最佳的.如需生成绝对唯一的 ID,请使用 md5() 函数". 下面方法返回结果类似:5DDB650F-4389-F4A9-A100-501EF1348872 functi

PHP生成唯一ID的三种方法

1.md5(time() . mt_rand(1,1000000)); 这种方法有一定的概率会出现重复 2.php内置函数uniqid() uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID. w3school参考手册有一句话:"由于基于系统时间,通过该函数生成的 ID 不是最佳的.如需生成绝对唯一的 ID,请使用 md5() 函数". 下面方法返回结果类似:5DDB650F-4389-F4A9-A100-501EF1348872 com_create_guid()是p

PHP获取时间戳和微秒数以及生成唯一ID

microtime函数 描述:返回当前Unix时间戳和微秒数 语法:mixed microtime( [ bool $get_as_float ] ) //直接输出 echo microtime(); //得到的是 如:0.26672100 1585622985 前面是当前微秒数,后面是正常时间戳,中间以空格分隔开 //如果带有参数(布尔型参数) echo microtime(true); //输出结果:1585623020.7408 刚才的微秒数就会以浮点数的形式表现在原有的时间戳之后 浮点数

python学习之-- 生成唯一ID

以下以2种方法生成唯一ID def uuid_method(): """第一种方法""" import uuid return str(uuid.uuid1()) print(uuid_method()) def time_method(): """第二种方法""" import time, hashlib m = hashlib.md5() m.update(bytes(str(tim

PHP生成唯一ID的方法

PHP自带生成唯一id的函数:uniqid() 它是基于当前时间微秒数的 用法如下: echo uniqid(); //13位的字符串 echo uniqid("php_"); //当然你可以加上前缀 echo uniqid("php_", TRUE); //如果第二个参数more_entropy为true则生成23位字符串 但是它生成的标识有可能不是唯一的,所以很多人会: //这是第一种简单的方法,当然用sha1()函数也可以. echo md5(uniqid()

twitter的snowflake算法

推特的工程师snowflake也提出了一个在分布式系统中生成唯一序列的方法: java中的UUID也是一种可取的方法,他的缺点是序列号太长了. snowflake算法最原始的形式是用scala语言写的https://github.com/twitter/snowflake/releases/tag/snowflake-2010 核心代码为其IdWorker这个类实现,其原理结构如下,分别用一个0表示一位,用—分割开部分的作用: 1 0---0000000000 0000000000 000000