当前位置: 首页 > 科技观察

一篇让你学会雪花算法的文章

时间:2023-03-11 22:18:43 科技观察

前言大家好,我是盼盼!之前用过rand和srand生成伪随机数。伪随机数的序列是固定的。今天我将学习生成真正的随机数。熵池使用/dev/urandom生成随机数值。/dev/urandomLinux下的熵池,所谓熵池就是当前系统下的环境噪音,描述了一个系统的混乱程度。环境噪声由这些方面组成,例如内存使用、文件使用、不同类型进程的数量等。随机数的值可以使用/dev/urandom生成。/dev/urandomLinux下的熵池,所谓熵池就是当前系统下的环境噪音,描述了一个系统的混乱程度。环境噪声由这些方面组成,例如内存使用、文件使用、不同类型进程的数量等。#include#includeintmain(){intrandNum=0;intfd=0;for(inti=0;i<5;i++){fd=open("/dev/urandom",O_RDONLY);读(fd,(char*)&randNum,sizeof(int));close(fd);printf("randNumis%d\n",randNum);}return0;}运行结果:mapan@mapan-virtual-machine:~/c++$./a.outrandNumis94961710randNumis-523780773randNumis1542169420randNumis-1632410867每次打印的5个随机数都不一样,其实它的随机性不是很好。雪花算法生成的数字随机性很好,在分布式系统中通常会生成一个唯一的ID。Snowflake算法SnowFlake算法生成的ID是一个64位的整数,结构如下(每部分用“-”号分隔):0-00000000000000000000000000000000000000000-00000-00000-000000000001。最高位为符号位,正数为0,负数为1。一般生成的ID为正数,所以为0;41位时间戳部分,这个是毫秒时间,一般实现Stamp不会存储当前时间,而是时间戳的差值(当前时间-固定开始时间),这样生成的ID可以从a开始较小的值;41位时间戳可以使用69年,(1L<<41)/(1000L606024365)=69年;10位节点部分,Twitter使用前5位作为数据中心标识,后5位作为机器标识,可部署1024个节点;12位序号部分支持同一毫秒内同一节点可生成4096个ID;/*snowflakeID生成策略毫秒时间41位+机器ID10位+毫秒序列12位。0415164+------------+------+------+|time|pc|inc|+------------+------+------+前41bits是以微秒为单位的时间戳。接下来的10位是预配置的机器ID。最后12bits是累加计数器。machineineid(10bits)表示最多1024台机器同时生成id,sequencenumber(12bits)也表示一台机器1ms最多生成4096个id。*注意,因为使用了位移计算,所以需要64位操作系统。否则生成的ID可能不正确*/#include#include#include#include#include#include#include#include#include#include#include#includestructgloble{intglobal_int:12;uint64_tlast_stamp;intworkid;intseqid;};voidset_workid(intworkid);pid_tgettid(void);uint64_tget_curr_ms();uint64_twait_next_ms(uint64_tlastStamp);intatomic_incr(intidid);uint64_th"structdeglobleg_linfo;#^(-1L<<12L))//L表示长型4095voidset_workid(intworkid){g_info.workid=workid;}pid_tgettid(void)//获取线程ID{returnsyscall(__NR_gettid);}uint64_tget_curr_ms()//获取毫秒{structtimevaltime_now;gettimeofday(&time_now,NULL);uint64_tms_time=time_now.tv_sec*1000+time_now.tv_usec/1000;returnms_time;}uint64_twait_next_ms(uint64_tlastStamp){uint64_tcur=0;do{cur=get_curr_ms();}while(cur<=lastStamp);returncur;}intatomic_incr(intid)//累积{__sync_add_and_fetch(&id,1);returnid;}uint64_tget_unique_id(){uint64_tuniqueId=0;uint64_tnowtime=get_curr_ms();//获取当前毫秒数uniqueId=nowtime<<22;//填写时间戳部分//0x3ff1023,二进制对应1111111111//100二进制000000000000000000000001100100//先执行班次uniqueId|=(g_info.workid&0x3ff)<<12;//填充节点部分if(nowtime