上周和公司技术同事们作了次《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. 一款 App 开发到上架

    随着互联网时代的发展,越来越多的 App 诞生啦.App 是手机软件的简称,手机主流的有 iOS.Andriod. 开发一个 App 需要哪些步骤呢?下面我和大家分享一下. 一.APP 的 idea( ...

  2. Python笔记22-----高阶函数

    1.sorted(排序对象,key=):排序对象可以是类别,也可以是字符串和字典,key为自定义排序,如:[key=abs,按绝对值排序][key=lambda x:x[1],按排序对象的第二个值排序 ...

  3. sql修改字段值

    update dfw_USER_ACCOUNTS set USER_INTEGRAL="20" where USER_INTEGRAL="17"

  4. JAVA中各个包的主要作用

    00:48:0800:48:1022013013-06-282013-06-2800:48:182013-06-2800:48:20  java.util是JAVA的utility工具包 java.l ...

  5. Python - def 函数

    1.def 函数 如果我们用代码实现了一个小功能,但想要在程序代码中重复使用,不能在代码中到处粘贴这些代码,因为这样做违反了软件工程中 DRY原则. Python 提供了 函数功能,可以将我们这部分功 ...

  6. Python中的全局变量与局部变量的区别

    全局变量与局部变量两者的本质区别就是在于作用域 用通俗的话来理解的话, 全局变量是在整个py文件中声明,全局范围内都可以访问 局部变量是在某个函数中声明的,只能在该函数中调用它,如果试图在超出范围的地 ...

  7. 【hiho一下 第十一周】树中的最长路

    [题目链接]:http://hihocoder.com/problemset/problem/1050 [题意] [题解] 有一个经典的求树的直径的方法; 首先; 树的直径的两端的端点必然都在树的叶子 ...

  8. js cookie 设置

    (function () { function getCookie(name) { var start = document.cookie.indexOf(name + "="); ...

  9. Inflation System Properties

    https://blogs.oracle.com/buck/inflation-system-properties I wanted to write a quick post about the t ...

  10. BA-siemens-insight报警设置

    以0007001(DDC-B3-09)为例,介绍insight报警的设置方法: