创建一个比微软性能更好空间更少的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); }