我的游戏是一款浏览器策略游戏,因此其中的一切操作都依赖计时器运行。建筑、研究、飞行数小时的舰队、远征,皆是如此。而我在如何处理这些内容的问题上犹豫了两次。

最初根本没有工作进程。所有事情都在网页请求内部完成。你打开一个页面,服务器检查自你上次访问以来应该完成的内容,将其完成,然后向你展示结果。这种机制可行,而且当没人游玩时几乎不消耗任何成本。

后来我为队列添加了一个工作进程,有段时间两者并存。网页可以完成建筑,工作进程也能完成建筑。

这是我最不喜欢的版本,问题不在于性能。而在于同一件事有两个所有者。两个地方都能完成队列,意味着需要保持两处同步,可能出现两处竞争,修复任何Bug都要修改两处代码。每次改动一处,我都得记着另一处。

所以现在工作进程掌管一切带有计时器的内容,网页不再处理定时事件。我知道这样做扩展性更差。工作进程每秒都会遍历到期行,无论是否有人在线,凌晨三点也要承担这个成本。我有意选择这样,是因为受够了那些诡异的半完成状态带来的损失。

但有一件事我刻意没有迁移,那就是矿产生产。直到你查看时,它仍然是被实时计算出来的。原因很简单:迁移它意味着每次滴答都要遍历所有行星,而不是只遍历到期的那些——而我大约有5000颗行星。

所以最终我采用了拆分方案。回过头看,我认为这个拆分就是真正的规则:

如果其他玩家能看到它的发生,或者它有截止时间,就由工作进程掌管。比如舰队抵达某玩家星球、研究完成并影响你的分数、远征结算——这些都不能等你登录后再处理。

如果只有拥有者能读取它,就在读取时计算。我的金属数量只有我自己和间谍报告能看见,而这两者本身就已经走读取路径了。

后半部分需要付出的代价是,我的日数据会非常不均衡。一个无人访问的殖民地好几天不产生任何收益,然后在某天终于有人打开时,一笔结清所有积累。周总数是对的,但单日数据不准。我每天差异一次通过维护终身计数器来解决这个问题。

目前我这边一次滴答耗时50到100毫秒,也就是说用掉了每秒可用时间的大约5%到10%。感觉还算安全,但老实说,我根本不知道真正的瓶颈在哪里。

所以对我来说,真正的问题是:这种方案到底会从何时开始造成麻烦?是玩家数量、行星数量、一个滴答内到期的行数,还是某个我尚未想到的因素?