上周和公司技术同事们作了次《Coding for Speed》技术分享,本来这只是再普通不过的技术探讨和交流(虽然挂了个颇有噱头的名称),但分享的时候逻辑没理好,语速很快,时间也太紧,因此难言是合格的“分享”、“探讨”,所以我觉得有必要以简短的文章形式对原 PPT 作点补充,即便分享的内容很少也很简单。

  本文将按原 PPT 的内容顺序分别作扩展说明或阐述,部分敏感信息将隐去,或只会简单提及。

  

  作本技术分享的初衷,一是在工作中了解及接触了一些我个人认为可优化改进的代码或设计,二也想能和同事们作一些技术方面的交流探讨,三我本人一直对性能这个议题颇有兴趣。

  约七、八年前还在做端游的时候,我和几个同事时有“蛋疼的”纯写/内嵌汇编以优化某些函数,或测试比拼 VC、Delphi、LLVM/CLang(C++Builder) 甚至 ICC(Intel C++ Compiler) 等编译生成的程序运行速度,而现在恐怕极少还有技术同仁去折腾这些了吧,(大部分时候)硬件已足够快、编译器优化也足够优秀,多数时候我们只要能正确的设计/使用/选用合适的技术方案和数据结构/算法,基本上不大会有性能方面的问题(尤其是考虑到现今大部分甚至绝大部分游戏的在线人数等远比不了以前,并发压力等小了很多)。

  当然,譬如休闲类的移动网络游戏,交互也(远)没有 MMORPG 复杂。

  

  以上所列这些软件、程序、算法甚至指令集等,几乎都有“快”、“高性能”等标签,如 std::map 底层实现即是用的红黑树,LZ4 HC 的解压速度是 zlib 的好几倍而压缩率只小一点点,TCMalloc 和 FastMM 都是非常高效的内存管理器,还有 Id Software 那著名的 InvSqrt 函数,和 Chrome 的底层脚本引擎 V8...等等。

  

  性能实在是很广很深的话题,在这方面我仅仅只是个有丁点经验的菜鸟而已。结合公司项目具体情况和诸同事技术及经验背景等因素,我将对查找表、位图算法、缓存及 IO 优化等方面和大家作探讨交流,并抛砖引玉分享 2 个我曾经想到的勉强也算“性能优化”的“优化”做法。

  

  简而言之,查找表即是预先将某些数据计算好,待需要的时候直接读取即可,譬如我以前写的 2D 绘制引擎(AGE),就预先计算了 0~360° 的 Sin/Cos 值等。很多时候,以少量的空间成本换取性能上的提升不失是个好做法(反之亦然),而这也是很基础很常用的“优化技术”。

  

  还记得以前重构某端游的任务系统时,我使用了位图来存储每个角色的任务标记位,譬如可用 2 个 bit 位来表示单个任务的完成情况(00 未接、01 已接、10 已放弃、11 已完成等),于是只需 1KB 的空间几乎就能存储每个玩家所有的任务完成情况了,而获取每个任务的状态也非常简单快速。

  

  

  

  从 Memory Hierarchy 简略图可以看出,越靠近 CPU,速度越快但容量越小,而 Jeff Dean 给出的数据更加直观。相较寄存器少及小的先天限制(多数时候对寄存器的使用是由编译器去作的优化),好的局部性能使程序有着更好的性能(cache 的功劳),譬如精简的循环通常有较好的时间和空间局部性(当然,循环展开是另外的优化话题了,它能有效减少分支预测失败带来的性能损耗)。

  

  较之 register 及 cache 的“不接地气”,明显内存(DRAM)就“平易近人”许多(想想 Redis),譬如游戏服务器完全可以(考虑)以适当的空间成本(内存占用)来提升负载能力,以优化改造之前同事写的某登录服务器为例,其做法是当客户端请求登录时,登录服务器会先从数据库查询用户数据然后再验证,而这步操作(相较而言)明显比较耗时,远比不上直接从内存读取的速度(譬如可以 hashtable 存取),所以可以考虑在登录服务器启动时,载入近几天登陆过游戏的用户数据至内存,当客户端请求登录时,若内存中没有此玩家数据,则再去数据库获取并将之放入内存,于是后续便只需读取内存(当然,每条玩家数据会占用多少内存空间,完全可以估算或测试)。而譬如密码,数据库保存的是其哈希值,但客户端登录时上传的是明文密码(通讯封包当然加密了,不过明文密码这个必然不好),于是登录服务器在验证时还需要将明文密码作哈希等处理然后再比较,我也顺带的将这个步骤作了优化,针对每个账号,当其登录请求第一次验证通过时,直接将其明文密码也缓存,于是以后的登录验证,直接比较明文密码即可,无需再进行哈希校验等。

  

  考虑到磁盘 IO 的低效(及延长硬盘寿命),和减轻数据库等压力,我们应重视及运用 Buffer 和 Batch 机制,譬如若有持续、频繁的写文件之类需求,可以先将它们存入缓冲区(Buffer),每隔一小段时间再 Flush 到磁盘,再譬如若有频繁的更新数据表记录的需求,若时效要求不严,完全可以事务的方式作批量更新等。

  

  有些端游、页游能绘制(鼠标所指)人物的轮廓,我也曾尝试写 shader 实现这种效果,但后来想到,以类似字体描边的做法不就可以实现么,而且写起来更简单,绘制引擎也能作 Batch Rendering 优化。

  简单提一下字体描边的做法,譬如在 (x,y) 处绘制文字,那么只需在 (x, y-1)、(x+1,y-1)、(x+1,y)、(x+1,y+1)、(x,y+1)、(x-1,y+1)、(x-1,y)、(x-1,y-1) 处分别再以描边颜色绘制一遍该文字,即能展现所谓“描边”效果了。

  网络游戏通常会对 AOI 作优化,而这些优化大多是数据结构和算法类的,譬如 MMORPG,可能有上百张地图,但很多时候,玩家大多集中在几个主城和副本地图里,但那些没有玩家的地图场景仍然会有 AOI 等,所以如果只对有玩家的地图作 AOI 等操作,应是能优化服务器的承载能力的。

  

  

  对于第二个问题,可能 XOR(异或) 是个好方法。

Coding for Speed 技术分享的更多相关文章

  1. fir.im Weekly - 8 个不能错过的 iOS / Android 技术分享

    本期 fir.im Weekly 收集了 2 月下旬新鲜出炉的 iOS /Android 技术分享.源码等,iOS 中图片技术的解压缩.逆向实战.iOS SDK 实践,Android架构思考.Andr ...

  2. 技术分享 | 在GreatDB分布式部署模式中使用Chaos Mesh做混沌测试

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1. 需求背景与万里安全数据库软件GreatDB分布式部署模式介绍 1.1 需求背景 混沌测试是检测分布式系统不确定性.建 ...

  3. fir.im Weekly - 新开发时代,需要什么样的技术分享

    "2016年,当我们迎来了如Xcode 8.Swift 3.SiriKit.Android N.Android Instant Apps.React Native等诸多移动开发技术.开发工具 ...

  4. 【转发】网易邮箱前端技术分享之javascript编码规范

    网易邮箱前端技术分享之javascript编码规范 发布日期:2013-11-26 10:06 来源:网易邮箱前端技术中心 作者:网易邮箱 点击:533 网易邮箱是国内最早使用ajax技术的邮箱.早在 ...

  5. CDN技术分享

    CDN技术分享目录 网络应用服务发展 CDN技术 1.CDN是什么?为什么我们需要它?(简介) 2.CDN能做什么?(作用) 3.CDN是如何工作?(原理) 4.CDN有那些具体应用?(应用) 我们项 ...

  6. 【转】apache kafka技术分享系列(目录索引)

    转自:  http://blog.csdn.net/lizhitao/article/details/39499283   估计大神会不定期更新,所以还是访问这个链接看最新的目录list比较好 apa ...

  7. 感知开源的力量-APICloud Studio开源技术分享会

    2014.9.15 中国领先的“云端一体”移动应用云服务提供商APICloud正式发布2015.9.15,APICloud上线一周年,迎来第一个生日这一天,APICloud 举办APICloud St ...

  8. HTML5学堂 全新的HTML5/前端技术分享平台

    HTML5学堂 全新的HTML5/前端技术分享平台 HTML5学堂是做什么的? HTML5学堂~http://www.h5course.com~由多名热爱H5的讲师们组成的一个组织.致力于构建一个前端 ...

  9. 内部技术分享的 PPT

    本文的基础是搞了一次内部的技术分享,在此也分享一下本次的PPT的一些内容.先列一下大概内容吧. EF-Code First API(WCF.WebAPI) Xaml MVVM AOP Xamarin. ...

随机推荐

  1. 使用 Laravel 5.5+ 更好的来实现 404 响应

    译文首发于 使用 Laravel 5.5+ 更好的来实现 404 响应,转载请注明出处! Laravel 5.5.10 封装了两个有用的路由器方法,可以帮助我们为用户提供更好的 404 页面.现在,当 ...

  2. js严格模式下判断数据类型

    function isType(type) { return function (content) { let t = Object.prototype.toString.call(content). ...

  3. 【Manthan, Codefest 18 (rated, Div. 1 + Div. 2) C】Equalize

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] Swap操作显然只能对(i-1,i)执行才有用. 不然直接将i翻转以及j翻转 显然比直接交换更优. 那么现在我们就相当于有两种操作. ...

  4. 洛谷——P1115 最大子段和

    https://www.luogu.org/problem/show?pid=1115#sub 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入输出格式 输入格式: 输入文件ma ...

  5. Android开发之使用BroadcastReceiver实现开机自己主动启动(源码分享)

    上一节已经介绍过BroadcastReceiver实现实时监听电量的功能,这节就来介绍一下假设实现开机自己主动启动的功能.这个比监听电量还简单不少 (1)在清单文件注冊权限 <uses-perm ...

  6. what we benefit from big data

    大数据玩的是什么,趋势,故障,寿命? 物联网拉动的是终端厂商的销量,作为终端设备生产商(OEM).无论是汽车.手机.家电行业.最有理由推动物联网的普及,可是作为传统行业,玩"网"并 ...

  7. 关于 xftp 上传文件时,仅仅是上传了0字节的问题

    有两次,上传的时候出现了问题.能上传.可是上传过去的文件都是0字节.查看了各种配置,都是正常的:百思不得解: 后来想起近期在linuxserver运行apt-get update时,中间曾失败过,于是 ...

  8. 字节与字符_字节流与字符流_ASCII与Unicode_GB2312_GBK_GB18030_BIG-5

    字节(Byte):通常将可表示经常使用英文字符8位二进制称为一字节. 一个英文字母(不分大写和小写)占一个字节的空间,一个中文汉字占两个字节的空间. 符号:英文标点2占一个字节,中文标点占两个字节. ...

  9. 火狐浏览器中加入httprequest的方法

    今天弄了非常久就才装好. 以下的样例是以 window为样例的,mac的也是这样, 下载好火狐之后点击右上角的菜单 想到httprequest是个插件,就点击附加组件 搜索出来之后找到httprequ ...

  10. QT 随笔

     1. 设置窗体属性,无边框 | 置顶 setWindowFlags(Qt::FramelessWindowHint); setWindowFlags(Qt::FramelessWindowHin ...