1. 程式人生 > >C語言實現分散式自增有序的唯一ID生成演算法-snowflake演算法

C語言實現分散式自增有序的唯一ID生成演算法-snowflake演算法

轉自:http://blog.csdn.net/wallwind/article/details/49701397

之前有人問我設計一個分散式的遞增的唯一id生成。想了半天不知道,偶然一個同事說起snowflake演算法,我百度了一下,很簡單高效。

參考

https://github.com/twitter/snowflake

於是,我自己用c語言隨便實現了一下,還沒有達到工業級別,需要細化,但是基本能用了,上程式碼。

  1. /* 
  2.     snowflake 
  3.     ID 生成策略 
  4.     毫秒級時間41位+機器ID 10位+毫秒內序列12位。 
  5.     0 41 51 64 +-----------+------+------+ |time |pc |inc | +-----------+------+------+
     
  6.     前41bits是以微秒為單位的timestamp。 
  7.     接著10bits是事先配置好的機器ID。 
  8.     最後12bits是累加計數器。 
  9.     macheine id(10bits)標明最多隻能有1024臺機器同時產生ID,sequence number(12bits)也標明1臺機器1ms中最多產生4096個ID, * 
  10.       注意點,因為使用到位移運算,所以需要64位作業系統,不然生成的ID會有可能不正確 
  11. */
  12. #include <stdio.h>
  13. #include <pthread.h>
  14. #include <unistd.h>
  15. #include <stdlib.h>
  16. #include <sched.h>
  17. #include <linux/unistd.h>
  18. #include <sys/syscall.h>
  19. #include <errno.h>
  20. #include<linux/types.h>
  21. #include<time.h>
  22. #include <stdint.h>
  23. #include <sys/time.h>
  24. struct  globle  
  25. {  
  26.     int global_int:12;  
  27.     uint64_t last_stamp;  
  28.     int workid;  
  29.     int seqid;  
  30. };  
  31. void set_workid(int workid);  
  32. pid_t gettid( void );  
  33. uint64_t get_curr_ms();  
  34. uint64_t wait_next_ms(uint64_t lastStamp);  
  35. int atomic_incr(int id);  
  36. uint64_t get_unique_id();  

  1. #include "snowflake.h"
  2. struct globle g_info;  
  3. #define   sequenceMask  (-1L ^ (-1L << 12L))
  4. void set_workid(int workid)  
  5. {  
  6.  g_info.workid = workid;  
  7. }  
  8. pid_t gettid( void )  
  9. {  
  10.     return syscall( __NR_gettid );  
  11. }  
  12. uint64_t get_curr_ms()  
  13. {  
  14.     struct timeval time_now;  
  15.     gettimeofday(&time_now,NULL);  
  16.     uint64_t ms_time =time_now.tv_sec*1000+time_now.tv_usec/1000;  
  17.     return ms_time;  
  18. }  
  19. uint64_t wait_next_ms(uint64_t lastStamp)  
  20. {  
  21.     uint64_t cur = 0;  
  22.     do {  
  23.         cur = get_curr_ms();  
  24.     } while (cur <= lastStamp);  
  25.     return cur;  
  26. }  
  27. int atomic_incr(int id)  
  28. {  
  29.     __sync_add_and_fetch( &id, 1 );  
  30.     return id;  
  31. }  
  32. uint64_t get_unique_id()  
  33. {  
  34.     uint64_t  uniqueId=0;  
  35.     uint64_t nowtime = get_curr_ms();  
  36.     uniqueId = nowtime<<22;  
  37.     uniqueId |=(g_info.workid&0x3ff)<<12;  
  38.     if (nowtime <g_info.last_stamp)  
  39.     {  
  40.         perror("error");  
  41.         exit(-1);  
  42.     }  
  43.     if (nowtime == g_info.last_stamp)  
  44.     {  
  45.         g_info.seqid = atomic_incr(g_info.seqid)& sequenceMask;  
  46.         if (g_info.seqid ==0)  
  47.         {  
  48.             nowtime = wait_next_ms(g_info.last_stamp);  
  49.         }  
  50.     }  
  51.     else
  52.     {  
  53.         g_info.seqid  = 0;  
  54.     }  
  55.     g_info.last_stamp = nowtime;  
  56.     uniqueId |=g_info.seqid;  
  57.     return uniqueId;  
  58. }  
  59. int main()  
  60. {  
  61.     set_workid(100);  
  62.     int size;  
  63.     for (;;)  
  64.     {  
  65.         uint64_t unquie = get_unique_id();  
  66.         printf("pthread_id:%u, id [%llu]\n",gettid(),unquie);  
  67.     }  
  68.     return;   
  69. }  

支援原子自增操作。

多執行緒情況下,可以將workid進行移位加上執行緒ID。

更多文章歡迎訪問:http://blog.csdn.net/wallwind