创建一个比微软性能更好空间更少的GUID

几年前写过C++版本并测试都没问题,见我以前的链接:http://blog.csdn.net/monster877/article/details/23067189
现在翻译成C#版本,创建10万个GUID的时间只需要3ms左右,C++的或许速度更快,具体算法如下:

1
using System; 3 using System.Collections.Generic; 4 using System.Diagnostics; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Test 10 { 11 12 //自定义GUID 13 public class MyGuid 14 { 15 /** 16 本程序可以生成64位全游戏大世界全局唯一ID,适合在分布式服务器集群中产生唯一ID 17  特点比微软自带的GUID要节省一倍的空间,即只需要64位的int即可,因此基本上在游戏服务器领域可以抛弃微软的那个GUID了 18 支持每秒生成4096个,在此条件基础上这辈子都不会产生相同的ID 19 20 由 时间戳+服务器区号+平台号+本地递增序号 组成 21 22 时间戳 32bit 23 服务器区号 12bit 24 平台号 8bit 25 递增序号 12bit 26 */ 27 private static ulong c_mark_time_stamp = 0xffffffff00000000;/*时间戳掩码*/ 28 private static ulong c_mark_district = 0x00000000fff00000;/*服务器区号掩码*/ 29 private static ulong c_mark_plat = 0x00000000000ff000;/*服务器里的平台号掩码*/ 30 private static ulong c_mark_base = 0x0000000000000fff;/*本地ID编号掩码*/ 31 private static uint c_baseId = 0;/*本地ID*/ 32 private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 33 34 //生成整个世界里全局唯一的ID district:服务器区号,platform:平台号 [如果游戏只接一个平台,则此平台号可以是服务器集群里的服务器类型编号] 35 public static ulong NewGuid(uint platform, uint district) 36 { 37 ulong timeStamp = (ulong)(DateTime.UtcNow- Jan1st1970).TotalSeconds;//获取自古以来的时间戳 38 ulong newId = ((timeStamp << 32) & c_mark_time_stamp) | ((district << 20) & c_mark_district) | ((platform << 12) & c_mark_plat) | (c_baseId & c_mark_base); 39 40 c_baseId++; 41 42 return newId; 43 } 44 } 45 class Program 46 { 47 static void Main(string[] args) 48 { 49 ulong guid = MyGuid.NewGuid(1, 1); 50 } 51 } 52 }

有人嫌每秒只能4096个少了,可以改成这样就可以每秒100多万了:

     public class MyGuid
        {
            /**
              本程序可以生成64位全游戏大世界全局唯一ID,适合在分布式服务器集群中产生唯一ID
             特点比微软自带的GUID要节省一倍的空间,即只需要64位的int即可,因此基本上在游戏服务器领域可以抛弃微软的那个GUID了
              支持每秒生成1048576个,在此条件基础上这辈子都不会产生相同的ID

                由 时间戳+大区号+小区号+本地递增序号 组成

                时间戳 32bit
                大区号 4bit
                小区号 8bit
                递增序号 20bit 

                支持大区16个,每个大区下支持256个小区,每个小区里支持每秒生成1048576个唯一ID
              */
            private static ulong c_mark_time_stamp = 0xffffffff00000000;/*时间戳掩码*/
            private static ulong c_mark_big_district = 0x00000000f0000000;/*大区号掩码*/
            private static ulong c_mark_small_district = 0x000000000ff00000;/*小区号掩码*/
            private static ulong c_mark_base = 0x00000000000fffff;/*本地ID编号掩码*/
            private static uint c_baseId = 0;/*本地ID*/
            private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

            public static ulong NewGuid(uint bigDistrict, uint smallDistrict)
            {
                ulong timeStamp = (ulong)(DateTime.UtcNow - Jan1st1970).TotalSeconds;//获取自古以来的时间戳
                ulong newId = ((timeStamp << 32) & c_mark_time_stamp) | ((bigDistrict << 28) & c_mark_big_district) | ((smallDistrict << 20) & c_mark_small_district) | (c_baseId & c_mark_base);

                c_baseId++;

                return newId;
            }
        }

 

最后再贴一下适合大世界的版本,支持根据guid反推所在服务器信息哦
    //服务器类型
    public enum ServerType
    {
        DB = 1,     //数据库服务器
        Logic = 2,  //逻辑服务器
        World = 3,  //世界服务器
        AC = 4,     //平台认证服务器
        Proxy = 5,  //网关服务器
        Center = 6, //中心服务器
        Record = 7, //记录服务器
    }
    //自定义GUID
    public class MyGuid
    {
        /**
          本程序可以生成64位全游戏大世界全局唯一ID,适合在分布式服务器集群中产生唯一ID,也适合分区分服的服务器,可自由更改掩码与占位调节
         特点比微软自带的GUID要节省一倍的空间,即只需要64位的int即可,因此基本上在游戏服务器领域可以抛弃微软的那个GUID了
          支持每秒生成65536个,在此条件基础上这辈子都不会产生相同的ID

          由 时间戳+服务器类型号+服务器ID号+本地递增序号 组成

          时间戳 32bit
          服务器类型号 4bit [允许16种不同类型的服务器]
          服务器编号 12bit  [同一类型服务器允许4096台]
          递增序号 16bit   [该位数决定了每秒允许65536个不同的guid]
        */
        private static ulong c_mark_time_stamp = 0xffffffff00000000;/*时间戳掩码*/
        private static ulong c_mark_server_type = 0x00000000f0000000;/*服务器类型掩码*/
        private static ulong c_mark_server_id = 0x000000000fff0000;/*服务器编号掩码*/
        private static ulong c_mark_base = 0x000000000000ffff;/*本地ID编号掩码*/
        private static uint c_baseId = 0;/*本地ID*/
        private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

        //生成唯一ID
        public static ulong NewGuid(ServerType server, uint id)
        {
            uint serverType = (uint)server;
            ulong timeStamp = (ulong)(DateTime.UtcNow - Jan1st1970).TotalSeconds;
            ulong newId = ((timeStamp << 32) & c_mark_time_stamp) | ((serverType << 28) & c_mark_server_type) | ((id << 16) & c_mark_server_id) | (c_baseId & c_mark_base);

            c_baseId++;

            return newId;
        }
        //根据唯一ID获取所在服务器类型与服务器编号
        public static void GetServer(ulong guid, out ServerType type, out uint id)
        {
            type = (ServerType)((guid & c_mark_server_type) >> 28);
            id = (uint)((guid & c_mark_server_id) >> 16);
        }
    }

 




C++版本:

const u_int64_t c_mark_time_stamp = 0xffffffff00000000;/*时间戳掩码*/
const u_int64_t c_mark_district = 0x00000000fff00000;/*服务器区号掩码*/
const u_int64_t c_mark_plat = 0x00000000000ff000;/*服务器里的平台号掩码*/
const u_int64_t c_mark_base = 0x0000000000000fff;/*本地ID编号掩码*/


u_int64_t gen_new_guid()
{
    static u_int32_t baseId = 0;
    baseId++;
    u_int64_t timeStamp = (u_int64_t)time(NULL);
    u_int32_t districtNum = 1;/*这个服务器区号可以根据实际情况设置或者获取*/
    u_int32_t platNum = 1;/*这个平台号可以根据实际情况设置或者获取*/
    u_int64_t newId = ((timeStamp << 32)&c_mark_time_stamp) | ((districtNum << 20) & c_mark_district) | ((platNum << 12) & c_mark_plat) | (baseId & c_mark_base);
}

 

 

posted @ 2015-10-25 11:49  孤心诣  阅读(594)  评论(0编辑  收藏  举报