免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: wlmqgzm
打印 上一主题 下一主题

[C++] 读性能超过Memcached 65%, 单核也超过redis, 支持日志支持掉电保护,欢迎试用 [复制链接]

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
51 [报告]
发表于 2016-05-24 08:38 |只看该作者
光靠你的一些描述不明白细节的

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
52 [报告]
发表于 2016-05-24 13:09 |只看该作者
本帖最后由 wlmqgzm 于 2016-05-24 17:10 编辑

回复 51# hellioncu

呵呵, 总算有人来踩踩了.

由于这个项目是学习和练手项目, 代码随意性比较强, 很多试验性质的库都拿来测试, 期望能够沿用到一些目前世界最先进水平的东西, 而不是拿十年前的技术练手.
代码 修改也比较大, 代码一直也没有稳定下来, 一直到现在, 连最底层File_Mapping层的代码, 包括接口还在不断的变, 昨天还修改了File_mapping_read实现大块数据的Zero copy, 也是在追求一种极致和最佳方案.

因此, 主要是记录思路的变化, 修改和废弃的代码, 远远超过留下来的代码, 高并发下高性能是公认的难题, 这个领域是非常困难的, 国内一直也没有类似Oracle这样牛的数据库开发公司和高手,
很多资料也缺乏, 又是个人开发, 我觉得数据库开发主要是思路问题,
类似 Leveldb, mongodb, innodb 有很多东西都值得学习, 然后, 拿里面最核心最有价值的思路, 然后学习, 实践, 最终推出一个集中全部优点的产品.

这次设计是 C++软件领域 最新技术的堆砌:
1)目前主要采用了  mongodb的 File_mapping 高性能IO读写技术.测试缓冲读性能1.6GByte/s, 缓冲写性能1.1GByte/s, 无缓冲磁盘写350MByte/s, 无缓冲磁盘读700MByte/s (已经实现)
2)采用了读写分离的存储层设计, 彻底去掉了mongodb的大锁, File_mapping读, 实现无锁并发, Zero Copy,  File_mapping写, 实现单线程写, 其他线程写缓冲队列输入, 实现最高性能的Wait_free无等待并发...(已经实现)
3)采用了LevelDb 数据分层, 一次性写入, 以及 不断合并技术, 实现完全消灭随机写, 只有顺序写, 对SSD的寿命有很大提高, 也可以实现最大化的写入速度, 实现极高的插入性能....(正在写代码, 部分实现...)
4)采用了内存中只存放索引, 减少物理内存占用, 数据由Mapping缓冲, 数据部分可不用放在内存中, 利用SSD的极高随机读性能, 单机实现10亿级别以上数据量的处理.....(正在写代码, 部分实现...)
5)采用了 innodb 日志offset 作为事务进度的指标, 以及commit事务隔离的思路, 并在自己的代码中也采用类似的技术思路, 为第2个版本提供MVCC做好准备.(准备第2个版本中实现, 第1个版本预留空间和定义)
6)采用了目前世界上比较前沿, 技术难度非常大, 国内还很少实践的 Lock_free, Wait_free 高性能无锁无等待队列技术, 作为线程间通讯. (已经实现, 已经全部采用Wait_free_queue)
7)采用了完全 智能化 对象 的设计思路, 并减少代码层次, ....实现了智能化对象, , File_Mapping_write无锁空间扩展, 文件数量自动增加和大小自动扩展, 以及多个File_mapping_read对象无锁自动跟踪扩展的技术,
各种比较新的对象设计思路 (正在写代码, 部分实现....)
采用了NOSQL的字段名field_name(/field_id)下推到底(每个Row记录)的设计, 以便为今后 任意新增/删除字段, 不需要全表更新.....(部分实现, 正在写代码....)
9)采用了目前压缩和解压缩速度最快的压缩工具包LZ4, 作为存储层的压缩工具, 以便减少IO流量, 增加缓冲的效率, 进而提供更快的IO性能. 每秒解压缩性能500MByte. (已经实现)
10)采用了目前速度最快的crc32c硬件校验技术(intel SSE4.2指令), 每秒校验速度1.6GByte(已经实现)
11)采用了目前高性能网络库Boost Asio, 实现每秒单连接PingPong测试11.2万QPS, 4核CPU下PingPong测试多连接87万QPS的性能(已经实现)
..............

所以, 希望大家有什么好的新技术和新思路推荐一下, 谢谢......





   

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
53 [报告]
发表于 2016-05-25 22:33 |只看该作者
本帖最后由 wlmqgzm 于 2016-05-25 23:03 编辑

下面是做的unsigned long long, unsigned int 压缩程序,  大约可以压缩一半的字节数,
这部分代码的压缩原理是: 整数可能只使用了一部分低位字节, 高位经常为零, 因此, 一个整数可以表示为非零字节数+非零字节的方式来表达.
  1. #ifndef _union_integer_hpp
  2. #define _union_integer_hpp


  3. //  使用联合处理所有的压缩整数, 性能会比较高
  4. union Union_long
  5. {
  6.   unsigned long long ulong1;
  7.   unsigned int uint1;
  8.   unsigned short ushort1;
  9.   unsigned char uchar1;
  10.   long long long1;
  11.   int  int1;
  12.   short short1;
  13.   char  char1;
  14.   unsigned char uchars[ sizeof( long long ) ];
  15. };

  16. union Union_int
  17. {
  18.   unsigned int uint1;
  19.   unsigned short ushort1;
  20.   unsigned char uchar1;
  21.   int  int1;
  22.   short short1;
  23.   char  char1;
  24.   unsigned char uchars[ sizeof( int ) ];
  25. };


  26. union Union_short
  27. {
  28.   unsigned short ushort1;
  29.   unsigned char uchar1;
  30.   short short1;
  31.   char  char1;
  32.   unsigned char uchars[ sizeof( short ) ];
  33. };

  34. #endif // _union_integer_hpp
复制代码

  1. #include "union_integer.hpp"

  2. #ifndef _compress_integer_hpp
  3. #define  _compress_integer_hpp


  4. class Compress_integer:  public boost::noncopyable
  5. {
  6. public:
  7.   static  unsigned long   get_ulong( const unsigned char *chars_in );
  8.   static  unsigned int       get_uint( const unsigned char *chars_in );
  9.   static  unsigned short get_ushort( const unsigned char *chars_in );
  10.   static  unsigned int   make_out( const unsigned long ulong_in, unsigned char *chars_out );
  11.   static  unsigned int   make_out( const unsigned int uint_in, unsigned char *chars_out );
  12.   static  unsigned int   make_out( const unsigned short ushort_in, unsigned char *chars_out );

  13.   static  int self_test( void );
  14. };


  15. Compress_integer    compress_integer;


  16. //  以下为压缩方式存储的读处理
  17. //  返回值就是取到的长度数据, chars_in[0]就是实际低位数据长度
  18. unsigned long Compress_integer::get_ulong( const unsigned char *chars_in  )
  19. {
  20.   unsigned int  uint_char_length  = chars_in[0];
  21.   if( uint_char_length==0 )   return 0;
  22.   if( uint_char_length>sizeof( unsigned long) )  {
  23.     std::string  str_msg = "compress ulong length should be ";
  24.     str_msg += std::to_string( sizeof( unsigned long) );
  25.     str_msg += ". but uint_char_length=";
  26.     str_msg += std::to_string( uint_char_length );
  27.     error_message_str( str_msg );
  28.     return 0;
  29.     }

  30.   Union_long   union1;
  31.   union1.ulong1 = 0;   //  先清零
  32.   for( unsigned int i=0; i<uint_char_length; ++i )  {
  33.     union1.uchars[i] = chars_in[i+1];
  34.     continue;
  35.     }
  36.   return   union1.ulong1;
  37. }


  38. unsigned int Compress_integer::get_uint( const unsigned char *chars_in  )
  39. {
  40.   unsigned int  uint_char_length  = chars_in[0];
  41.   if( uint_char_length==0 )   return 0;
  42.   if( uint_char_length>sizeof( unsigned int) )  {
  43.     std::string  str_msg = "compress uint length should be ";
  44.     str_msg += std::to_string( sizeof( unsigned int) );
  45.     str_msg += ". but uint_char_length=";
  46.     str_msg += std::to_string( uint_char_length );
  47.     error_message_str( str_msg );
  48.     return 0;
  49.     }
  50.   Union_int   union1;
  51.   union1.uint1 = 0;   //  先清零
  52.   for( unsigned int i=0; i<uint_char_length; ++i )  {
  53.     union1.uchars[i] = chars_in[i+1];
  54.     continue;
  55.     }
  56.   return  union1.uint1;
  57. }


  58. unsigned short Compress_integer::get_ushort( const unsigned char *chars_in  )
  59. {
  60.   unsigned int  uint_char_length  = chars_in[0];
  61.   if( uint_char_length==0 )   return 0;
  62.   if( uint_char_length> sizeof( unsigned short ) )  {
  63.     std::string  str_msg = "compress ushort length should be ";
  64.     str_msg += std::to_string( sizeof( unsigned short) );
  65.     str_msg += ". but uint_char_length=";
  66.     str_msg += std::to_string( uint_char_length );
  67.     error_message_str( str_msg );
  68.     return 0;
  69.     }
  70.   Union_short   union1;
  71.   union1.ushort1 = 0;   //  先清零
  72.   for( unsigned int i=0; i<uint_char_length; ++i )  {
  73.     union1.uchars[i] = chars_in[i+1];
  74.     continue;
  75.     }
  76.   return   union1.ushort1;
  77. }


  78. //   生成压缩的ulong, chars_out1要预先留下9个字节, 使用1--9字节, 多数情况下只使用2个字节
  79. //   返回chars_out生成的总长度
  80. unsigned int  Compress_integer::make_out( const unsigned long ulong_in, unsigned char *chars_out  )
  81. {
  82.   if( 0==ulong_in )  {
  83.     chars_out[0] = 0;
  84.     return 1;
  85.     }

  86.   unsigned int int_char_length = 0;
  87.   const unsigned char *chars_in = reinterpret_cast<const unsigned char*>( &ulong_in );
  88.   int n = sizeof( ulong_in );
  89.   for( int i=n-1; i>=0; --i )  {
  90.     if( '\0'  == chars_in[i] )  continue;  //  最高位连续的'\0', 则跳过
  91.     for( int j=0; j<=i; ++j )  {  // 拷贝非零的低位
  92.       chars_out[j+1] = chars_in[j];
  93.       ++int_char_length;
  94.       continue;
  95.       }
  96.     break;
  97.     }
  98.   chars_out[0] = int_char_length;  //  第1个字节表示长度
  99.   ++int_char_length;
  100.   return  int_char_length;
  101. }


  102. //   生成压缩的uint, chars_out1要预先留下5个字节, 使用1--5字节, 多数情况下只使用2个字节
  103. //   返回chars_out生成的总长度
  104. unsigned int   Compress_integer::make_out( const unsigned int uint_in, unsigned char *chars_out  )
  105. {
  106.   if( 0==uint_in )  {
  107.     chars_out[0] = 0;
  108.     return 1;
  109.     }

  110.   unsigned int int_char_length = 0;
  111.   const unsigned char *chars_in = reinterpret_cast<const unsigned char*>( &uint_in );
  112.   int n = sizeof( uint_in );
  113.   for( int i=n-1; i>=0; --i )  {
  114.     if( '\0'  == chars_in[i] )  continue;  //  最高位连续的'\0', 则跳过
  115.     for( int j=0; j<=i; ++j )  {  // 拷贝非零的低位
  116.       chars_out[j+1] = chars_in[j];
  117.       ++int_char_length;
  118.       continue;
  119.       }
  120.     break;
  121.     }
  122.   chars_out[0] = int_char_length;  //  第1个字节表示长度
  123.   ++int_char_length;
  124.   return  int_char_length;
  125. }


  126. //   生成压缩的ushort, chars_out1要预先留下3个字节, 使用1--3字节, 多数情况下只使用2个字节
  127. //   返回chars_out生成的总长度
  128. unsigned int   Compress_integer::make_out( const unsigned short ushort_in, unsigned char *chars_out  )
  129. {
  130.   if( 0==ushort_in )  {
  131.     chars_out[0] = 0;
  132.     return 1;
  133.     }

  134.   unsigned int int_char_length = 0;
  135.   const unsigned char *chars_in = reinterpret_cast<const unsigned char*>( &ushort_in );
  136.   int n = sizeof( ushort_in );
  137.   for( int i=n-1; i>=0; --i )  {
  138.     if( '\0'  == chars_in[i] )  continue;  //  最高位连续的'\0', 则跳过
  139.     for( int j=0; j<=i; ++j )  {  // 拷贝非零的低位
  140.       chars_out[j+1] = chars_in[j];
  141.       ++int_char_length;
  142.       continue;
  143.       }
  144.     break;
  145.     }
  146.   chars_out[0] = int_char_length;  //  第1个字节表示长度
  147.   ++int_char_length;
  148.   return  int_char_length;
  149. }


  150. //  这个是写程序的时候, 写的测试程序, 用于测试验证代码的正确性.  实际测试正常.
  151. //  测试程序有利于编写高质量的代码, 并且可以在集成测试前, 测试模块的正确性.  也便于验证版本升级等 代码修改后的正确性.
  152. int  Compress_integer::self_test( void )
  153. {
  154.   unsigned long ulong1;
  155.   unsigned int  uint1;
  156.   unsigned int  uint_ret;
  157.   unsigned int  uint_tmp;
  158.   unsigned short ushort1;
  159.   std::string   str_msg;
  160.   std::vector<unsigned char>  vt_char;
  161.   vt_char.resize( 100, '\0' );

  162.   ulong1 = 65535;
  163.   uint_ret = make_out( ulong1, &vt_char[0] );
  164.   if( uint_ret != 3 || vt_char[0] != 2 || vt_char[1] != 255 || vt_char[2] != 255 )  {
  165.     str_msg = "make_out( const unsigned long ulong_in, char *chars_out  );    test failed. ";
  166.     str_msg += ", uint_ret=";
  167.     str_msg += std::to_string( uint_ret );
  168.     str_msg += ", vt_char[0]=";
  169.     uint_tmp = vt_char[0];
  170.     str_msg +=  std::to_string( uint_tmp );
  171.     str_msg += ", vt_char[1]=";
  172.     uint_tmp = vt_char[1];
  173.     str_msg +=  std::to_string( uint_tmp );
  174.     str_msg += ", vt_char[2]=";
  175.     uint_tmp = vt_char[2];
  176.     str_msg +=  std::to_string( uint_tmp );
  177.     error_message_str( str_msg );
  178.     return -1;
  179.     }
  180.   ulong1 = get_ulong( &vt_char[0] );
  181.   if( ulong1 != 65535 )  {
  182.     error_message( "static  unsigned long  get_ulong( const char *chars_in  );    test failed. ");
  183.     return -2;
  184.     }

  185.   ulong1 = 65536;
  186.   uint_ret = make_out( ulong1, &vt_char[0] );
  187.   if( uint_ret != 4 ) {
  188.     str_msg = "uint_ret != 4,   uint_ret=";
  189.     str_msg += std::to_string( uint_ret );
  190.     error_message_str( str_msg );
  191.     return -3;
  192.     }
  193.   ulong1 = get_ulong( &vt_char[0] );
  194.   if( ulong1 != 65536 )  {
  195.     error_message( "static  unsigned long  get_ulong( const char *chars_in  );    test failed. ");
  196.     return -2;
  197.     }

  198.   ulong1 = 3;
  199.   uint_ret = make_out( ulong1, &vt_char[0] );
  200.   if( uint_ret != 2 || vt_char[0] != 1 || vt_char[1] != 3  )  {
  201.     error_message("make_out( const unsigned long ulong_in, char *chars_out  );    test failed. ");
  202.     return -1;
  203.     }
  204.   ulong1 = get_ulong( &vt_char[0] );
  205.   if( ulong1 != 3 )  {
  206.     error_message( "static  unsigned long  get_ulong( const char *chars_in  );    test failed. ");
  207.     return -2;
  208.     }

  209.   ulong1 = 3423732746321463216L;
  210.   uint_ret = make_out( ulong1, &vt_char[0] );
  211.   ulong1 = get_ulong( &vt_char[0] );
  212.   if( ulong1 != 3423732746321463216L )  {
  213.     error_message( "static  unsigned long  get_ulong( const char *chars_in  );    test failed. ");
  214.     return -2;
  215.     }

  216.   uint1 = 65535;
  217.   uint_ret = make_out( uint1, &vt_char[0] );
  218.   if( uint_ret != 3 || vt_char[0] != 2 || vt_char[1] != 255 || vt_char[2] != 255 )  {
  219.     str_msg = "test failed. ";
  220.     str_msg += ", uint_ret=";
  221.     str_msg += std::to_string( uint_ret );
  222.     str_msg += ", vt_char[0]=";
  223.     uint_tmp = vt_char[0];
  224.     str_msg +=  std::to_string( uint_tmp );
  225.     str_msg += ", vt_char[1]=";
  226.     uint_tmp = vt_char[1];
  227.     str_msg +=  std::to_string( uint_tmp );
  228.     str_msg += ", vt_char[2]=";
  229.     uint_tmp = vt_char[2];
  230.     str_msg +=  std::to_string( uint_tmp );
  231.     error_message_str( str_msg );
  232.     return -1;
  233.     }
  234.   uint1 = get_uint( &vt_char[0] );
  235.   if( uint1 != 65535 )  {
  236.     error_message( " test failed. ");
  237.     return -2;
  238.     }

  239.   uint1 = 65536;
  240.   uint_ret = make_out( uint1, &vt_char[0] );
  241.   if( uint_ret != 4 ) {
  242.     str_msg = "uint_ret != 4,   uint_ret=";
  243.     str_msg += std::to_string( uint_ret );
  244.     error_message_str( str_msg );
  245.     return -3;
  246.     }
  247.   uint1 = get_uint( &vt_char[0] );
  248.   if( uint1 != 65536 )  {
  249.     error_message( "test failed. ");
  250.     return -2;
  251.     }

  252.   uint1 = 342373274;
  253.   uint_ret = make_out( uint1, &vt_char[0] );
  254.   uint1 = get_uint( &vt_char[0] );
  255.   if( uint1 !=  342373274 )  {
  256.     error_message( "test failed. ");
  257.     return -2;
  258.     }

  259.   ushort1 = 65535;
  260.   uint_ret = make_out( ushort1, &vt_char[0] );
  261.   if( uint_ret != 3 || vt_char[0] != 2 || vt_char[1] != 255 || vt_char[2] != 255 )  {
  262.     str_msg = "test failed. ";
  263.     str_msg += ", uint_ret=";
  264.     str_msg += std::to_string( uint_ret );
  265.     str_msg += ", vt_char[0]=";
  266.     uint_tmp = vt_char[0];
  267.     str_msg +=  std::to_string( uint_tmp );
  268.     str_msg += ", vt_char[1]=";
  269.     uint_tmp = vt_char[1];
  270.     str_msg +=  std::to_string( uint_tmp );
  271.     error_message_str( str_msg );
  272.     return -1;
  273.     }
  274.   ushort1 = get_ushort( &vt_char[0] );
  275.   if( ushort1 != 65535 )  {
  276.     error_message( " test failed. ");
  277.     return -2;
  278.     }

  279.   ushort1 = 53274;
  280.   uint_ret = make_out( ushort1, &vt_char[0] );
  281.   ushort1 = get_ushort( &vt_char[0] );
  282.   if( ushort1 != 53274 )  {
  283.     error_message( "test failed. ");
  284.     return -2;
  285.     }

  286.   return 0;
  287. }

  288. #endif  // _compress_integer_hpp

复制代码

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
54 [报告]
发表于 2016-05-25 23:24 |只看该作者
wlmqgzm 发表于 2016-05-25 22:33
下面是做的unsigned long long, unsigned int 压缩程序,  大约可以压缩一半的字节数,
这部分代码的压缩原理 ...


和Google的protobuf、我的DirectStruct思路差不多

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
55 [报告]
发表于 2016-05-26 00:43 |只看该作者
本帖最后由 wlmqgzm 于 2016-05-26 10:07 编辑

回复 54# BetonArmEE

对,     这部分整数压缩思路算是很多公司的新型接口都采用了.      ,  所以, 开源出来,

最近一两周代码中, 实现的 Wait_free, Lock_free 通用对象队列,  算的上技术含金量最高的, 使用了模板技术等, 性能上算彻底突破锁的瓶颈,

以前虽然利用Lock_free_queue做了一些代码, 主要是利用Boost的lock_free队列,只能适合POD对象, 从未自己实现过通用对象的Wait_free/Lock_free Queue,
这次实现了任意对象的Wait_free_queue, 算是对Boost库的拓展, 如果提交的话, 估计有进入Boost库代码的潜力.

主要的技术难点是:
1) shared_ptr对象在pop前需要保存起来, 以便实现 生产者 Fire and care nothing 发射后就不管了,   等消费者pop处理完毕, shared_ptr对象要自动释放.
2)生产者临时存放shared_ptr的对象, 无论是采用deque, list, 还是其他vector对象, 都不是线程安全的, 这里不能使用锁, 否则, 无锁队列就没有意义了.  那么这部分代码是如何在无锁的前提下无冲突安全工作的?
这些都是容易产生坑的地方, 那么就要想出来办法, 完全消灭这些坑.
3) 消费者pop消费掉对象后,  生产者临时存放shared_ptr的对象需要释放,  如何实现?
不能再创建一个队列反向通知, 这样的效率太低了, 那么, 一个单向队列, 如何让对端知道一些对象已经可以释放? 还不能释放已经pop, 但是正在处理的对象, 因此, 也不能完全依赖环形队列自身.
也不能依赖shared_ptr,   因为真正最底层的Wait_free队列最多只能存放64位整数(指针), shared_ptr本身就根本无法存放进Wait_free队列, 我的代码中实际实现在最底层Wait_free队列中传递的是shared_ptr保存对象的指针
为了实现 Wait_free, 生产者和消费者还不能有共享变量, 例如: 共享atomic,  否则, 就变成Lock_free了

总之, 封装实现一个任意对象的Lock_free / Wait_free 队列技术难度很高, 就是将上述的各个大坑全部填平, 然后拿出一套完整的解决办法.
就是因为目前已有的开源技术, 没有一家能够实现的, 所以, Boost目前没有提供通用对象的Lock_free/Wait_free队列.
实际上, 通用对象的Lock_free/Wait_free队列, 在实际开发中才是真正需要的, 各大公司就算有弄出来的, 基本都视为核心代码, 予以保密. 这个是解决高并发下高性能的核武器级别的开发辅助工具包. 对性能提升帮助是非常大的.


论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
56 [报告]
发表于 2016-05-26 10:46 |只看该作者
最近代码开发速度比较慢, 每天只有数百行, , 这样的话, 这个项目有可能要花更多的时间才能出第一个版本,

论坛徽章:
89
水瓶座
日期:2014-04-01 08:53:31天蝎座
日期:2014-04-01 08:53:53天秤座
日期:2014-04-01 08:54:02射手座
日期:2014-04-01 08:54:15子鼠
日期:2014-04-01 08:55:35辰龙
日期:2014-04-01 08:56:36未羊
日期:2014-04-01 08:56:27戌狗
日期:2014-04-01 08:56:13亥猪
日期:2014-04-01 08:56:02亥猪
日期:2014-04-08 08:38:58程序设计版块每日发帖之星
日期:2016-01-05 06:20:00程序设计版块每日发帖之星
日期:2016-01-07 06:20:00
57 [报告]
发表于 2016-05-26 11:05 |只看该作者
wlmqgzm 发表于 2016-05-26 10:46
最近代码开发速度比较慢, 每天只有数百行, , 这样的话, 这个项目有可能要花更多的时间才能出第一个版本, ...


要是都有用的话,每天数百行已经不少了。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
58 [报告]
发表于 2016-05-26 11:21 |只看该作者
回复 55# wlmqgzm

谁告诉你Boost.Lockfree只支持POD?
http://www.boost.org/doc/libs/1_61_0/doc/html/lockfree.html

另外再提醒你一下,new和delete不是lockfree的。

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
59 [报告]
发表于 2016-05-26 12:43 |只看该作者
回复 58# windoze

  boost::lockfree::queue<int>    d_lock_free_queue1(100);
  if( d_lock_free_queue1.is_lock_free() )  {
    std::cout<< "1 is lock_free!" <<std::endl;
    }
  else   std::cout<< "1 NOT lock_free!" <<std::endl;

  boost::lockfree::queue<std::shared_ptr<int> >    d_lock_free_queue2(100);
  if( d_lock_free_queue2.is_lock_free() )  {
    std::cout<< "2 is lock_free!" <<std::endl;
    }
  else   std::cout<< "2 NOT lock_free!" <<std::endl;


||=== Build: Release in mysql1 (compiler: GNU GCC Compiler) ===|
/usr/include/boost/lockfree/queue.hpp||In instantiation of ‘class boost::lockfree::queue<std::shared_ptr<int> >’
/var/cpp/mysql2/main.cpp|187|required from here|
/usr/include/boost/lockfree/queue.hpp|87|error: static assertion failed: (boost::has_trivial_destructor<T>::value)|
/usr/include/boost/lockfree/queue.hpp|91|error: static assertion failed: (boost::has_trivial_assign<T>::value)|
||=== Build failed: 2 error(s), 2 warning(s) (0 minute(s), 3 second(s)) ===|

实际就是编译无法通过, boost::lockfree::queue目前不支持shared_ptr

   

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
60 [报告]
发表于 2016-05-26 12:56 |只看该作者
本帖最后由 wlmqgzm 于 2016-05-26 13:07 编辑

回复 58# windoze

引用 译文: http://blog.csdn.net/chen19870707/article/details/40039401

TCMalloc:线程缓冲的Malloc

TCMalloc的版本同样的操作大约只需要50纳秒。

TCMalloc也减少了多线程程序中的锁竞争情况。对于小对象,已经基本上达到了零竞争。对于大对象,TCMalloc尝试使用恰当粒度和有效的自旋锁。

........如果自由列表不空,那么从移除列表的第一个对象并返回它。当按照这个快速通道时,TCMalloc不会获取任何锁。这就可以极大提高分配的速度,因为锁/解锁操作在一个2.8GHz Xeon上大约需要100纳秒的时间。

=====================================================================================

我的理解: 内存申请有时是存在锁的问题, 多数时候是不用锁的, 因为TCMalloc是基于线程预分配内存的, 只有预分配的内存用完的情况下, 才会申请锁, 申请更多的内存, 小概率" 有锁, 有等待",
这个部分Google的TCMalloc基本已经做的挺好.

确实是高手啊, 这个是Lock_free Wait_free代码里面唯一出现锁(小概率)的地方,  也不是没有彻底解决小概率锁的办法, 就是不够优雅, 例如: 自定义一个足够空间的Malloc, 这部分代码只能从这个空间申请和释放内存, 与其他代码隔离开,  

   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP