梦断代码--一个程序员的自白 (一)

梦断代码--一个程序员的自白 (一)


                                  --当一个有价值的人或事物逝去,缅怀他的人便为之立碑,写下墓志铭。
本文以此献给Protein。

    看过一本同样叫做《梦断代码》的书,英文名叫《dream in code》 我总觉得翻译得不准确。 在那本书中,讲述了一个软件项目Chandler失败的前后经历,让人读来扼腕叹息。 然而今天,这四个字不断地在我的脑海里盘旋,仿佛是为我这六年来的经历下一结语。

    在AIRMax启动时,我来到公司尚不足一年。经理让我参加一个叫AirData(后来也叫ADP)的项目,我对此也是跃跃欲试。然而一开始什么都没有准备好,除了让我们看一些资料外,还让我们看了一个叫DWF的项目代码。没想到,这一看就让我工作在上面好几个月。


    因为当时已经知道ADP中将有一个很重要的部分就是管理property,因此,我也就重点看了DWF的property部分。当时,美国那边提出ADP的性能和内存占用是很重要的,还特别提到要考虑如何缓存处理property。从我知道的信息来看,已经知道ADP是读写一个本地的文件包,并管理一系列property map的对象。对于这样的系统,数据规模方面的信息也是知道的,我觉得性能低下是难以想象的问题,或者说是不理解。不仅是我不理解,我认为美国同事也没想明白问题出在那里。而对一个不理解的问题,设定了一个解决方案则是更不可思议的。在我看来,这根本就是软件设计中的大忌。可是就是这样的错误,在后来的日子里一犯再犯。


    我既然有这样的认识,那么对于去研究设计一个所谓的缓存机制自然是毫无兴致。从我当时的判断来看,这是一个小而紧凑的系统,风险不大。因此,当务之急是搞清楚这个系统的职责范围,在整个大系统中的位置和功能。然后衡量非功能需求有哪些,是不是可以做到。对功能性需求,划定范围,犁清边界是重要的;对非功能需求做保底计算,确定可行性是重要的。当然经验也是重要的,可是不分析问题的原因,而是把问题本身作为一种恐慌而传播,在我看来就是不成熟和不职业的体现。可是我当时没法做出这些反驳,因为我们面对的都是“经验丰富的,资深的“美国前辈。更何况,中国这边也有轻看自己的气氛,要求我们要”谦虚“。不管怎么说,我认为我们的当务之急应该是“理解”要做的项目。


    在几乎对系统一无所知的情况下来设计这样一个缓存系统,很显然只是在做无用功,浪费时间。可我没法拒绝做,只好说,这样一个缓存机制太容易了,我可以立刻示范一个,不值得研究。因为我知道他们也无法验证我的示范。我当然无法针对一个还不存在的系统做cache,但是,将来做这个系统的人现在正在做的事情,和他们遇到的问题还是可以分析的,也是值得分析的。一半是赌气,一半是较真,我把目标对准DWF,那个带给他们不安的部分。我花了几天时间,在DWF的property系统里弄了个cache机制,缓解内存占用的问题。


    当时的做法是,给property(名称的问题,实际上是property map)弄了个proxy,这样,就有机会不立刻加载property map,而是延后到实际访问的时候。为了进一步降低内存,还把已经加载,但是暂时不用的property map交换到外部磁盘去,我简单地弄了个文件做交换。而C++的花哨技巧也帮了忙,不需要改动其他部分代码,只要重新build就好了。


    这个做法实际上是有许多问题的,降低内存使用的同时也可能降低了性能--虽然实测性能稍有改善,这是延迟加载带来的收益。代价也是明显的,就是复杂性和不平稳。另一个问题是,代码风格是全新的,别人将来恐怕难以维护。但是结果却出人意料地得到了美国同事的认可--我猜他们只是被花哨的C++代码唬住了,真够悲哀的--于是我就暂时地工作在了DWF上面。


    DWF的代码在我看来,颇有些叠床架屋的味道。虽然满是腐朽坏味,但是如果能从中吸取教训,也不失为非常好的教材。既然工作在了DWF上,那就既来之,则安之吧。我被要求继续对DWF做优化。很快,我找到一个确实有价值的地方。考虑有许多property map对象,而这些map中的Property name名称是大量重复的,如果能够用flyweight模式的话,会节约大量内存。当然的想法就是能不能直接做在DWF的string类型中。结果,一看这string,就发现有严重的性能问题。于是做了一个性能测试,把报告发给了美国同时。没想到,这件事让我将来尝到了苦果。 

    当时DWF快接近尾声,我也不想在这么关键的部位大动手脚。正好利用之前做的那个property proxy,做了一个property name的string pool。这一次的结果测试效果非常好,最好可以节约50%左右的内存,最差的case的大约是16%左右,平均也有35%左右吧,记不太清楚了。


    我之前做的那个将property map交换出去的方案,也得到了新的指示:让我研究SQLite,把外部交换文件用SQLite替换,以期得到更好的性能和内存占用。我非常郁闷:我设计的交换文件其实很简单,内存中维护一个property到外部block的map,外部block就一个接一个放在文件中。我很难相信SQLite就一定会更好,更何况要付出不菲的代价。在研究了几天SQLite后,我还是从了,切换到了SQLite,直接使用其B+树的接口。这当然不是一帆风顺的,特别是B+树的API并没有详细的文档,结果也不乐观,唯一的收获,可能就是SQLite可以制定其内存占用量了。这种收获在我看来根本就毫无价值。关键的败笔是,事情变得更复杂了。


    正是这个SQLite的方案,因为一直没能得到理想的结果,在使用B+接口方面,在事务控制方面,在锁文件配置方面,都遇到过问题。这让我在DWF多耽搁了许多时间。这时美国的O同事已经开始ADP了,正在设计一个property map系统的数据类型部分。说是期望我能够早点去ADP,并有一个“challenge”希望我可以解决。终于在又拖了一周后,我终于在所有人之后,转战ADP了。


    大地陷入沉寂,噩梦刚刚开始。

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 43
    评论
我可以为您提供一个Python绘制哆啦A梦的示例代码,您可以在Python环境运行它: ```python import turtle # 设置画笔的初始位置和角度 turtle.penup() turtle.goto(-100, 150) turtle.left(90) # 绘制哆啦A梦的头部 turtle.pendown() turtle.begin_fill() turtle.color('#00a0de') turtle.circle(120) turtle.end_fill() # 绘制哆啦A梦的脸部 turtle.penup() turtle.goto(-70, 70) turtle.begin_fill() turtle.color('white') turtle.circle(70) turtle.end_fill() # 绘制哆啦A梦的眼睛 turtle.penup() turtle.goto(-50, 110) turtle.begin_fill() turtle.color('black') turtle.circle(10) turtle.end_fill() turtle.penup() turtle.goto(50, 110) turtle.begin_fill() turtle.color('black') turtle.circle(10) turtle.end_fill() # 绘制哆啦A梦的鼻子 turtle.penup() turtle.goto(-10, 70) turtle.begin_fill() turtle.color('#ffde00') turtle.circle(20) turtle.end_fill() # 绘制哆啦A梦的嘴巴 turtle.penup() turtle.goto(-70, 30) turtle.pendown() turtle.color('black') turtle.right(90) turtle.circle(70, 180) # 绘制哆啦A梦的胡须 turtle.penup() turtle.goto(-70, 70) turtle.pendown() turtle.right(120) turtle.forward(60) turtle.penup() turtle.goto(-70, 50) turtle.pendown() turtle.right(60) turtle.forward(60) turtle.penup() turtle.goto(-70, 30) turtle.pendown() turtle.right(60) turtle.forward(60) # 绘制哆啦A梦的身体 turtle.penup() turtle.goto(-100, -20) turtle.begin_fill() turtle.color('#00a0de') turtle.pendown() turtle.forward(200) turtle.right(90) turtle.forward(100) turtle.right(90) turtle.forward(200) turtle.right(90) turtle.forward(100) turtle.end_fill() # 绘制哆啦A梦的铃铛 turtle.penup() turtle.goto(0, -20) turtle.begin_fill() turtle.color('#ffde00') turtle.circle(25) turtle.end_fill() # 绘制哆啦A梦的手臂 turtle.penup() turtle.goto(-100, -120) turtle.pendown() turtle.begin_fill() turtle.color('#00a0de') turtle.forward(40) turtle.right(90) turtle.forward(80) turtle.right(90) turtle.forward(40) turtle.right(90) turtle.forward(80) turtle.end_fill() turtle.penup() turtle.goto(100, -120) turtle.pendown() turtle.begin_fill() turtle.color('#00a0de') turtle.forward(40) turtle.left(90) turtle.forward(80) turtle.left(90) turtle.forward(40) turtle.left(90) turtle.forward(80) turtle.end_fill() # 绘制哆啦A梦的脚 turtle.penup() turtle.goto(-80, -220) turtle.begin_fill() turtle.color('#00a0de') turtle.pendown() turtle.forward(60) turtle.right(90) turtle.forward(40) turtle.right(90) turtle.forward(60) turtle.right(90) turtle.forward(40) turtle.end_fill() turtle.penup() turtle.goto(20, -220) turtle.begin_fill() turtle.color('#00a0de') turtle.pendown() turtle.forward(60) turtle.right(90) turtle.forward(40) turtle.right(90) turtle.forward(60) turtle.right(90) turtle.forward(40) turtle.end_fill() # 隐藏画笔 turtle.hideturtle() ``` 您可以将此代码复制并粘贴到Python编辑器,然后运行它以绘制哆啦A梦的图像。
评论 43
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值