i007.cc

i007.cc

优先队列-降维打击

WOD代码review结果(重要!)

编号 问题 优先级 修改难易程度
322001 stringstream对象使用方式不对, 现在是每次使用ss对象都构造一个, 实际上不需要构造一个, 可以通过以下方式优化
static thread_local std::stringstream ss;
ss.clear();
ss.str(“”);
较高 简单
工作量比较大
322002 避免C String的使用
底层被频繁调用的库函数, 要避免使用c string当作API
可以将接口改成const std::string&的形式, 减少不必要的拷贝
较高 简单
322003 log库内一条log使用了多个stringstream对象
做了多次拷贝
因为log库使用地方非常多, 所以这个优化很有必要
较高 简单
322004 消息解码尽量移到网络线程来做, 给主线程足够的时间比例来处理逻辑
现在网络线程只是在做分帧, 应该把解码也放到网络线程内
可以通过两步优化:
第一步先做rsb的缓冲, 只需要增加一个指针成员, 在消息被push到主循环之前调用get_rsb()函数完成解码工作
第二步, 可以在分帧之后直接完成解码, 少一次内存拷贝, 这个修改比较复杂
较高 第一步简单
第二步较难, 看实际情况, 可以不做
322005 发送尽量从主线程里面挪开
现在发送大部分都是在主线程内完成, 只有Socket缓冲区满了, 才会因为send失败而进入ET模式, 变成异步发送
需要将send的过程从主线程分离, 增加主线程处理逻辑消息的时间比例
做法是弄成asio类似接口的网络库, 或者简单一点的做法就是增加一两个发送线程
比较复杂
322006 base_server等依赖改成库/工程级别的依赖
现在这种源码级别的依赖, 会导致编译时间较长
比较简单
322007 DBServer派发Command给Worker的Queue, 改成通过Condition variable来通知
而不是通过pull/sleep来做
可以降低系统的消耗, 减少延迟, 提升worker的吞吐量
简单
322008 修改volatile关键字的代码, 换成std::atomicXXX形式
VC下volatile有atomic语义, GCC下没有
简单
但是工作量大
遗留代码很多
322009 传递std::string参数的代码修改成const std::string&或者std::string&
现在代码里面有多处传递std::string参数的函数
虽然拷贝一次, 程序运行没有问题, 但是效率比较低
中等 简单
322010 传递std::shared_ptr<T>参数的代码改成const std::shared_ptr<T>&
智能指针需要传递const引用
减少不必要的消耗
中等 简单
322011 const错误使用
代码里面有一些传递const参数的代码, 应该编写的时候少敲了一个&符号
参数不能传递const, 要传递就要传递const &
例如void f(const std::string&), 而不能写void f(const std::string)
简单
322012 减少malloc/new混用
这个在DB Server内很严重, 可以通过unique_ptr和shared_ptr来减少编写代码的复杂度
简单
322013 生成环境链接jemalloc/tcmalloc
系统内动态内存分配比较频繁, 建议生产环境链接上面两个库
简单
322014 正确使用range-based for
for(auto item : items) 这样的代码在服务器内出现多次
这种严格来讲是错误的代码, 要不然写auto&要不然写const auto&
不能直接写auto, 复杂对象会产生一次无效的拷贝, 而且有时候会导致一些很难查询的逻辑BUG
简单
要让程序员养成习惯
322015 MySQL escape string API修改
现在API是基于c string的, 难以编写逻辑
DBServer内有大量因为escape string写的new/delete
可以通过替换成std::string&来替代, 一方面提高编码的效率, 减少编码心智负担, 一方面还可以提高运行的效率(strtingstream对const char*需要求一次strlen, std::string自带length)
较高 简答
322016 .str().data()/.str().c_str()
需要禁止程序员手动调用string的data()函数和c_str()函数
这种编码习惯会导致多拷贝一次对象
服务器内有200+处这样的代码
较高 简单
322017 数据库表的初始化, 不需要stringstream对象
可以直接写:
const char* sql = “create table if not exists `table1`(”
“`mail_id` int,”
“`exp` int”
……
不需要通过stringstream来拼接
简单
322018 LOGI日志级别是不是写错了
现在info级别是5, 是最高级别, 比fatal都高, 这个是不是写错了?
简单
322019 逻辑处理有大量的LOGI(rsb.toString())代码
这种代码应该是调试时才用的, 线上环境如果每个逻辑消息都dump出来的话, 服务器应该会扛不住
简单
322020 RSB消息的toString()实现有缓冲区溢出风险
该函数内部有一个256字节的栈变量, 通过sprintf来格式化
如果消息过大, 是有可能破坏栈帧
非常高 简单
329001 auto使用导致的拷贝过多
现在很多auto都在做拷贝, 建议查看准确语义增加&, 减少不必要的拷贝
简单
量比较大
329002 禁止逻辑代码里面对json cpp的直接使用
现在对json这两个配置文件的使用, 是直接使用Json::Value对象去做动态的解析, 而不是在服务器启动时解析一次, 然后程序使用解析后的数据
导致技能初始化的时间过长
建议把json一次性解析成程序需要的对象, 而不是简单的映射(程序使用的时候还需要构造一次)
中等
329003 技能代码里面对make_shared的过多使用
例如SkillEvent对象内部, 有5个shared_ptr, 一个vector, 可以考虑将该对象内的vector<shared_ptr>改造成C数组, 减少new的次数
简单
但是需要查看代码确定哪些可以修改
329004 DBConnection对SQL语句的执行, 是一次性的, 没有考虑云数据库的可用性问题
需要对数据库不可用时做合适的处理(例如等待等), 否则该SQL语句就直接被抛弃了
云数据库在发生故障的时候, 会有短暂的不可用(通常时秒级)
简单
329005 GameZone上的Cell, 建议做惰性的初始化, 有实体在上面的时候再插入, 而不需要一次性构造一个很大的vector, 可以减少内存的使用 简单
329006 GameZone上Cell的单位是不是1米
如果是1米的话, 对象移动的时候, 经常会出入格子; 对象的移动需要经常计算AOI
给服务器造成不必要的负担
中等

发表回复