• 25 十一 2009 /  互联网技术

    昨天花了一下午的时间测试一个程序的执行效率,该程序是一个后台日志分析的程序,犯懒用php写的,毕竟php对文本处理效率很高(编写&执行),一开始担心php的数组按照键值查询效率低,所以使用memcache作为内存缓存来用。

    程序编写好后执行正常,当处理数据量上来以后,发现执行很慢。其它的项目中我也发现在压力测试时memcache会是瓶颈并导致很高的cpu占用,因此怀疑是否自己编译的php+memcached有问题,或者是其它问题。于是做了下面的测试。

    Trace for /logprocess/process_sessiontime_memcached.php
    Total Elapsed Time = 767.74
    Total System Time = 19.15
    Total User Time = 742.67

    Real User System secs/ cumm
    %Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name
    --------------------------------------------------------------------------------------
    69.2 531.12 531.12 520.74 520.74 6.94 6.94 92646 0.0057 0.0057 0 Memcached->set
    21.4 164.18 164.18 157.25 157.25 4.85 4.85 92646 0.0018 0.0018 0 Memcached->get

    从上面的数据能看出,这个程序php执行的瓶颈在memcache,而set操作更加有问题,接近70%的时间都在做set操作,难道真是使用的模块有问题嘛?我查过php的memcached模块,代码基本上就是一个连接,实质使用的还是libmemcached这个库的内容,所以如果要是有问题的话也肯定在libmemcached这个上面。但网上搜索后,无果,没有人说它有问题。

    后来细想,按照上面的数据折算,读写平均的话122.22次/秒,读单独是564.30次/秒,写单独是174.47次/秒,数据表现也算不错了。写慢是memcache以及被测试的程序逻辑有矛盾,我了解了一下,memcache会使用item(key+value)的长度做前期的定位,试想如果程序使得value长度不断变化,是否set会不断移动item所在的slab位置呢(将旧的变成过期,再按照新写入数据的流程写入新的item)?没有深度考究,但觉得值得怀疑;如果写操作所占用的cpu释放出来的话,读的效率应该可以更高,回头可以测试一下,估计能超过1千次/秒。

    总结上述,memcache使用要被仔细的规划,取长补短,如果随意使用的话未必能有好的效果。上面的程序其实就不应该用memcache,频繁的写不是memcache的强项,而分布式、多点频繁读取才是强项。

    说道缓存,所以我顺便又测试了Alternative PHP Cache(APC)的模式,还是刚才的程序,出来的结果是读写平均392.57次/秒,比memcache快3倍多,我没有出读写分离的数据,估计如果单读的话,应该还能再快一些,毕竟APC是本地缓存。因此,如果你的应用不需要分布式的话,APC是一个很好的选择,它能帮你在一台机器的情况下,保持并缓存每次php请求之间的数据。其次,它还是一个类似eAccelerator的代码opcode缓存模块,可以提高php代码执行速度。

    最后,回到我一开始没有考虑的解决方案,因为我不需要跟其它进程或者服务器共享我的数据,所以直接用php的数组,处理速度是多少呢?15,441次/秒!当然啦,内部就是一堆指针指来指去而已,我没有想到的是数组在很多无序的key中找value还是很快的,所以以后大家可以放心这么使用,只是注意配置文件中允许的php运行时占用的内存再调大点就好了。

    总结,任何设计要根据具体的应用需求来选择解决方案,选择时要考虑所选技术本身的特性,取其优点避其缺点。Memcache不适合做数据频繁变化的内存共享,一次写入多次读取的模式会更适合一些。Tokyo Tyrant / Tokyo Cabinet / Redis也许能用于频繁读写的情况,我还没有时间去评测;BTW,以前还使用Mysql内存表做这类事情多一点,希望能构建一个数据写入缓存机制,但是实际使用时还是有一些问题,所以有空再找找新的解决方案吧。

    最后说一句,就一句:在Memcache盛行的当今,Memcache不可滥用。

    Tags: , ,

  • 23 十一 2009 /  互联网技术

    脑子不好使,只能记录下来以后备用

    首先python有几个版本,我现在选择的是2.5版,版本越低,可选择的第三方支持包就越多,当然也要平衡,低版本也会有性能问题,或者小bug。2.6是3.0的过度版本,有很多新的特性但又兼容老的版本(3.0有些老版本的语法、特性就不支持了),所以权衡选择了2.5版。

    python自身的安装比较简单,在linux下就是通过源码编译就可以了,需要注意的是,python在linux系统下作为很底层的语言支持,通常系统会有一个版本默认已经安装了,如果你觉得那个版本够用就直接用,如果安装新的版本,最好不要改动或者覆盖那个版本。我一般都在/usr/local/python2.5目录下安装一个新的,然后ln -s /usr/local/python2.5/bin/python2.5 /usr/bin/python2.5,这样原有的版本和新的版本互不干扰。

    python的扩展包很多,一般分成两类,两种方法来安装
    1、扩展包是直接的源码包
    通常这种包解开后会有一个setup.py的文件,使用你希望安装这个扩展包的python版本来运行python setup.py install就可以完成安装,当然你也可以先python setup.py make再install,意思和linux下编译源代码的流程是类似的。

    2、.egg文件
    这种类似jar的代码包是一个叫easy_install的项目产生的,首先你可以下载并安装easy_install;如果你的easy_install是.egg结尾的,可以使用sh easy_install.egg来安装。如果是普通源码包就参考上面第一种方法安装。
    安装后会在 /bin/目录下多出来一个叫easy_install的脚本。你下载的.egg包就可以运行./easy_install xxx.egg来安装了。
    当然还有一个更简单的方法,就是./easy_install module_name,这样它就会在网上找到适当的模块进行自动安装并且保持模块之间的关联。
    easy_install除了网上查询包自动下载,后续的工作就是在 /lib/python2.5/site-packages/目录下的easy_install.pth文件中加入了.egg文件的关联而已,并且将.egg文件拷入上述这个目录,这样python在寻找软件包的时候就能找到并自动装载。

    BTW:有关Python MySQLdb模块
    上述安装方法很自然就可以将这个模块安装好,但是我的习惯不喜欢将mysql客户端的库放在默认的位置,导致实际python导入模块的时候会报错,这时候只需要将你的库文件路径加入/etc/ld.so.conf中,并且执行ldconfg -v就可以了。

    Tags:

  • 19 十一 2009 /  杂项

    over-working

    最近又听说有人因为工作劳累而驾鹤西游了,某公司危机公关忙得不亦乐乎,顿时觉得有点悲哀。

    记得Joel Spolsky在他的The Best Software Writing I这本书里面收录过一篇文章叫EA: The Human Story,主要内容是描述EA内部过渡加班的问题,并且用数字说明加班也许并不能提高工作效率,反而会降低工作效率,引发员工很多心理问题导致最后人员流失。

    个人认为公司不能将加班当做正常的一种工作手段,如果你在估算工作计划的时候就把加班考虑进去了,那你就丧失了所有缓冲时间;试想加班是计划的一部分的话,如果不能按照计划完成,你还有什么选择?

    人是有周期性的,长期在高度紧张的状态容易效率低下以及疲惫不堪,情绪会非常波动,整天只有身躯在办公室里坐着而思想不知道跑到那里去了,这样的表现公司是不愿意看到的,但老板通常会想念大家,希望7X24小时在公司能看到大家忙碌。停下来想一想,这样的效果好嘛?磨洋工对项目有意义嘛?

    在不能改变别人的情况下,你就需要自己注意,如果觉得累或者情绪不好,就干脆什么都停下来,休息,睡个觉,做点别的无关的事情,也许做着做着你就有新的工作思路以及冲动了。

    希望传闻的悲剧能被合理的解决,并且大家尽量避免悲剧的再度发生。

  • 27 十 2009 /  互联网技术

    原文链接:Nginx & Comet: Low Latency Server Push

    作者:Ilya Grigorik

    翻译:孙绍轩

    服务器推送(Server Push)是高效的、延迟低的数据交换方式。如果数据发送端与接收端都在互联网中公开可见,可以使用PubSubHubbubsimpler Webhook等方法完成任务。但是如果数据接收方在防火墙内、在内网或它只是一个浏览器(只可以向外发送数据请求,无法处理传入的数据),则实现服务器推送就更难了。如果你有冒险精神,你可以建立一个反向HTTP服务器。如果你寻求可靠的解决方案,也许你要等待HTML5的WebSocket’s API特性了。但如果你需要即刻可以实现的解决方案,你可以妥协一下,使用异步推送模式来代替,你可以使用Comet,也被称为反向Ajax、HTTP服务器推送或HTTP流。

    早在2006年Alex Russel提出了一个不坏的技术思路,那就是长连接(Comet)概念:从客户端发起并保持一个连接直到数据出现并传送(long polling),或者永远保持一个连接,通过它推送数据到客户端(streaming)。这两种方法的好处是数据传送非常及时。因此长连接技术广泛用于聊天应用(Facebook, Google, Meebo等)以及实现即时触发的机制。

    Nginx变成一个长连接服务器

    实现长连接服务比较大的问题是特殊的隐形需求以及事件驱动web服务器能否高效处理众多的长连接。Friendfeed的Tornado服务器是一个标准应用级服务器的好例子。另外,感谢Leo Ponomarev的努力,你现在可以用nginx_http_push_module插件使你的Nginx服务器变身成为一台完全功能的长连接服务器。

    使用自定义的一套框架结构,Leo的插件只提供两个对外的接口:一个是订阅者,一个是发布者。客户端连接Nginx服务器,创建针对一个频道的long-polling长连接并等待数据。同时,发布者只是简单的将数据使用POST方法提交给Nginx,插件收到数据后将它一个个发给等待的客户端。这表明发布者不需要直接传递数据,它只是一个简单的事件产生器!没有比这个更简单的方法了。

    还有更高的功能是,客户端和发布端可以建立任意的频道,并且插件也提供消息队列功能,这表明Nginx服务器会在客户端断线的情况下临时保存消息。队列消息可以按照时间、等待列表长度或内存限制大小来失效释放。

    NginxRuby配置例子

    一开始,你需要从源代码编译一个Nginx。解压源代码包,从GitHub获取插件的源码并放入Nginx的源码目录,然后使用下面的参数编译(./configure –add-module=/path/to/plugin && make && make install)。下一步,参考readme文件和协议文件,了解所有的参数选项。一个多客户端接收信息的配置例子如下:

    > nginx-push.conf

    # 内部发布点(保证私有或不对外公开)

    location /publish {

    set $push_channel_id $arg_id;      #/?id=239aff3 或类似的文本标示

    push_sender;

    push_store_messages on;            # 打开消息队列

    push_message_timeout 2h;           # 2小时后消息失效

    push_max_message_buffer_length 10; # 保存10条消息

    push_min_message_recipients 0;     # 清除前最小接收人数目

    }

    # 公开的长连接接收点

    location /activity {

    push_listener;

    # 一个频道编号能有多少客户端同时连接

    # – last: 只有最频繁请求的客户端能保持,其它连接返回409

    # – first: 只有最早连接的那个客户端可以保持,其它连接返回409

    # – broadcast: 任何数量的客户端连接都会是长连接

    push_listener_concurrency broadcast;

    set $push_channel_id $arg_id;

    default_type  text/plain;

    }

    当你编译配置好你的Nginx服务器,并且启动它,我们可以建立一个简单的广播场景,一个数据发送广播方,几个订阅信息接收方来测试我们的长连接服务器。

    > comet-push-consume.rb

    require ‘rubygems’

    require ‘em-http’

    def subscribe(opts)

    listener = EventMachine::HttpRequest.new(‘http://127.0.0.1/activity?id=’+ opts[:channel]).get :head => opts[:head]

    listener.callback {

    # 打印所获取的内容,并重新订阅这个频道

    # 使用last-modified头去忽略之前已经获取的数据。

    puts “Listener recieved: ” + listener.response + “\\n”

    modified = listener.response_header['LAST_MODIFIED']

    subscribe({:channel => opts[:channel], :head => {‘If-Modified-Since’ => modified}})

    }

    end

    EventMachine.run {

    channel = “pub”

    # 每5秒钟发布一个新的消息

    EM.add_periodic_timer(5) do

    time = Time.now

    publisher = EventMachine::HttpRequest.new(‘http://127.0.0.1/publish?id=’+channel).post :body => “Hello @ #{time}”

    publisher.callback {

    puts “Published message @ #{time}”

    puts “Response code: ” + publisher.response_header.status.to_s

    puts “Headers: ” + publisher.response_header.inspect

    puts “Body: \\n” + publisher.response

    puts “\\n”

    }

    end

    # 打开两个客户端

    subscribe(:channel => channel)

    subscribe(:channel => channel)

    }

    nginx-push.zip (完整的Nginx配置和Ruby代码)

    在上面的代码中,每5秒钟数据发布端向Nginx服务器发出新的事件,服务器将数据通过长连接转发给两个订阅的客户端。当消息发送到客户端,服务器会断开他们的连接,客户端会立即重连并等待下一次数据的到来。结果就是使用Nginx实现了一个数据发布端到客户端的实时消息推送机制!

    期待生产环境下的长连接服务

    Leo的模块还在开发期,还需要时间来稳定下来,但它是一个需要关注的项目。最近的更新计划都着重于bug修复,未来的计划里有描述要加入流的模式:代替现在每次数据获取后都要重连的情况(long polling),Nginx会保持连接,将数据一段段的实时传送给客户端。拥有这个功能后你能很方便的部署你自己的信息触发式API(例如:Twitter流)。

    最后,不要忘记数字不断增长的其它Nginx模块,或者如果你感兴趣的话,可以参考Evan Miller编写的指引来开发自己的Nginx模块。

    Tags: ,

  • 26 十 2009 /  互联网技术

    Software Developer 2.0 2009会议上以及之前参加的一些会议上看到一个现象,大厂商都开始敏捷了,如果你现在还徘徊是否要敏捷,我觉得可能为时已晚,你要立刻敏捷起来!

    SD2.0 2009上微软给大家介绍了Visual Studio 2010,从界面上来看沿袭了Office 2007的风格,工具条排列很花哨,也有一大堆微软经典的wizards,利用这些向导可以很方便的完成开发工作。一个被我关注的重点是VS2010整合了开发流程中除了编码以外的东西,比如版本控制、缺陷管理、UML建模等都融合进入这个集成开发环境,并且它还拥有敏捷开发的一些特性模板,单元测试模板用于测试驱动开发。不难看出微软为了方便开发者,将最近开发管理所需的功能都列入到它的VS2010里面去了,而且是全网络化的解决方案,开发人员之间是可以很方面的共享信息的。相信在微软内部也有团队在实施敏捷。

    IBM的一场演讲中也透露出,IBM内部软件开发也在实施敏捷,而讲演者Robert Degg来自Rational,他主要的工作就是在IBM内部帮助各个软件开发部门实施敏捷。

    通过网上的一些文档介绍,Google, Yahoo!, Facebook, Twitter, eBay等大型互联网公司都在实施敏捷开发并有些成效。敏捷已经不是两三年前大家都在观望的局面了,已经不是只有创业团队敢于尝试的一种开发方法了,渐渐的你会发现身边的软件公司都多少的运用敏捷开发的方法,你还犹豫什么?

    忽悠大家半天再来说说如何实施敏捷

    也许敏捷方法并不和你现在使用的方法有太大的差异,我认为我们要从小事出发,用敏捷方法解决我们现在特定的问题,这样才能积累所有人的信心继续朝着更高的方向改进。毕竟老板只会看效果,如果不能在短时间内达到效果,说到天花乱坠也没有用。下面列举一些可以注意的小点,你可以按照你具体的情况来选择实施。

    • 对待需求按照重要程度排序,一段时间内只完成确认的最终要的任务

    其实很多开发团队也是这么做的,只是敏捷方法提出频繁迭代的概念,让完成需求有一个特定的周期,并且这个周期要尽可能频繁的迭代。每个周期完成的是完整的事情,没有完成的百分之多少的概念,只有完成和没有完成。这样保证每个迭代有工作的产物,保证下一个迭代万一出现问题我也能拿出上一个迭代的成功产物。

    另外重要程度排序也会使得最重要的业务需求最先完成,不至于做的半天都是无用功。

    迭代周期中不加入其它新的变化导致在一段时间内足够的清净让开发人员来完成工作。

    • 测试驱动

    也许这个题目太大,你可以缩小化成自动单元测试,因为要自动测试所以你要写测试脚本,也许你会在写完程序后懒得写测试脚本所以把测试脚本编写在程序开发前面。选择一个适合的测试框架,你会很快达到这个目标。你会发现不必为了找一个bug花费很多的时间,如果你要查问题,就给自己一个假设,用这个假设实现一个测试来验证吧,逐渐的你的测试脚本会限制你,一有bug测试就无法通过了,你就不需要找而是直接修复发现bug。

    对于小团队,这里其实更重要的是让单元测试从无到有。

    • 配对编程

    也许你会对这个很怀疑,但我能说的是,这只是一个形式,如果你仔细观察,在你公司内部,也会经常因为某一个人解决不了一个问题而抓住另外一个人,两个人一弄就是一下午,也许问题已经解决了,两个人也会继续一段时间。配对本来就是一个很自然的事情。

    配对根本解决什么呢?

    1、人的经验问题,不可能都是全才,配对有利于带新人,或者让两个不同领域的开发人员能互相熟悉或产生升华。这点通常在配对前两个人一起设计而体现。

    2、代码复查;首先我相信大部分开发团队是没有这个独立的工作内容的,但它真的很重要,代码复查可以让所有人在一个编码标准下开发,复查可以让一些有问题的设计思路更早被发现,因为一个不好的设计并不会产生bug,但也许它影响了后续的性能或者灵活的可扩展性。因此如何引入代码复查而又不增加而外的开发负担呢?配对编程是个很好的方法。

    3、形成通才而不是很多专才;通常我们担心某些点没了某些人就不转了这种情况,一个是不利于公司管理,二来也不利于那个人发展(我因为精通某一个方面就弄要负责那个方面,也许我都已经厌倦了,但无法自拔,解脱只有辞职换工作了),配对编程的经验共享使得可以弱化上述问题,并且所有人被灌输的是你感兴趣的部分你都可以了解,不是对每个开发人员发展都有激励作用嘛?

    • 任务管理或缺陷管理

    也许这不算敏捷里面的东西,但它和敏捷开发密不可分,例如Scrum里面的burndown chart就是代表bug被解决的趋势。老外讲究的一个思路是:你如果想优化一个事情,就首先要弄清楚如何度量这个事情,只有度量的结果才能反馈你的改进是否有效。因此无处不在的数据会很直接的体现项目的状况。

    现成的有很多系统可以辅助你进行任务管理和缺陷管理,我推荐Trac,一个使用Python编写的集成系统,用于开发中知识共享,围绕它也可以找到很多第三方的插件来满足你的需求。

    ok,对比一下你的现状,也许你离敏捷并不遥远,只需要参考一下将好的东西吸取到你现在的过程中,就这么简单,开始行动吧,也许未来你也能创造出一个什么敏捷方法!

    Tags:

  • 26 十 2009 /  互联网技术

    上个星期参加为期三天的Software Developer 2.0 2009大会,我了解到各个手机系统平台提供商的现状,现归纳总结一下。

    Android

    Google推出的东西总是可以在那个领域溅起巨浪,Android以免费开放的原则推出,引起了众多人的关注,发布了两年后这个东西逐渐成熟起来,支持的手机也越来越多了。总体都往好的方面发展,中国地区的开发者可能更加关注,希望这个年轻的项目可以尽快开花结果。

    SymbianOS

    老牌智能手机操作系统大哥,被Nokia收购了以后沉默了一小段时间,变身成Symbian Foundation出现在我们面前,给大家的惊喜是,免费、开放,果真是被Google挤兑的不行了。计划明年2010年全部开放所有的系统代码和授权,个人估计山寨机又会更火,因为又有一个好用的系统平台可以选择了。BTW:Nokia最近出的手机真是没有什么新意,gphone和iphone两面夹击,够它受的了,祈祷吧。

    iPhone下的Coco touch

    苹果是相对封闭的,我们只能去写iphone或者ipod touch上面的应用,平台就看着眼馋吧,个人觉得这种封闭的、控制力很强的软硬结合物才能做出精品。

    Windows Mobile 6.5

    如果你是微软的崇拜者,你可以继续关注,不过总觉得PC上的一个概念移植到手机而不用手机的思路来设计一个系统的话,不会太好用。不过这个开发会是很简单,强大的Visual Studio永远是开发利器。这次开会也有幸看到Visual Studio 2010,大厂也开始敏捷了,呵呵。

    WebOS

    Palm借助WebOS推出Palm Pre新一代手机系统,一个巨人倒下了,如果能再次站起来的话,那会是非常强大。希望能看到这一天,因为Palm是最能体会移动设备操作的厂商,现在其它平台下很多操作都有palm的影子。期待它再次回到主力。

    BlackBerry

    封闭的软硬系统以及特定的应用场景,如果不是针对商业应用开发的开发者就不用太关注它了。

    总结

    平台还是很多的嘛,作为开发者的你也不能三心二意,专注在一个平台上先做大是我的忠告。至于选择哪个平台,那就要看自己的情况了。Android借助中国移动Ophone的力量蓄势待发,强烈的建议重点关注。iPhone如果你是做国外业务也可以关注,如果是关注国内市场就可以稍微晚一点再说,因为从联通对iphone的定价,我十分怀疑它有足够的运营能力能将这个优秀的平台在国内搞好(苹果也不是吃素的,一向会很强硬)。Symbian有足够的有开发经验的开发人员,想做应用找现成的人就好了,无需再自己研究,所以这个平台关注就好,只要你的应用有竞争力,补充上Symbian平台可以说是小菜一碟。

    让暴风雨来得更猛烈些吧,只有平台竞争更激烈,运营商竞争更激烈,才会有更多的好处落在用户和开发者身上,我们期待这一天早一些来临吧!

    Tags: , ,

  • 10 十 2009 /  互联网技术

    写在前面:

    总觉得学习英语要实践点什么,计划作为毕业印证我要翻译一本技术书籍。现在我还没有毕业,所以接下来的日子里,尝试翻译一些短文,热热身先。

    ———————华丽的分割线———————————-

    Python内建异常清单

    by Al Lukaszewski for About.com

    翻译:Yorgo Sun

    原文:http://python.about.com/od/pythonstandardlibrary/a/lib_exceptions.htm

    下面是一个完整的Python运行时会抛出的错误列表。大部分错误都可以一目了然,我添加了一些注释来使得它们更加清晰。这参考并扩展了Python 2.5文档中“内建异常”的章节。

    • BaseException: 所有内建异常的基础类。
    • Exception: 所有的内建的、非系统预置的异常均继承这个类,所有用户定义的异常也应该继承这个类。
    • StandardError: 所有内建异常的基础类,除了StopIteration,GeneratorExitKeyboardInterruptSystemExit StandardError 是继承Exception而来的。
    • ArithmeticError: 一些内建算术错误异常的基类,如: OverflowErrorZeroDivisionError,FloatingPointError.
    • LookupError: 当一个键值或索引在数组或序列中无效时所触发的所有异常的基类: IndexError,KeyError. 它也会由sys.setdefaultencoding()直接触发。
    • EnvironmentError: 所有能发生在Python系统之外的异常的基类:IOErrorOSError.
    • AssertionError: 当判定条件失败时,触发此异常。
    • AttributeError: 当一个属性被引用或赋值时出现错误会引发此异常(当一个对象不支持属性被引用或赋值时,会触发TypeError异常)
    • EOFError: 当内建函数(input() 或 raw_input())达到文件尾时触发此异常。(注意:文件对象的read() 和 readline()方法处理方法不同,当遇到到达文件尾部的情况时会返回空字符串)
    • FloatingPointError: 浮点操作失败时触发此异常。
    • GeneratorExit: 当调用生成器的close() 方法时,触发此异常。它直接继承了Exception 用于替代 StandardError ,毕竟这是一个技术手段并不是一个错误异常。 2.5版本新加特性。
    • IOError: 当I/O操作(如一个 print 语句、内建 open()函数或调用文件对象的某个方法)因为I/O相关的问题而失败时触发此异常,例如:“无此文件”或“没有足够的磁盘空间”。这个类继承于EnvironmentError
    • ImportError: 当 import 语句无法找到对应的模块定义或 from…import 无法找到对应名字的内容时触发此异常。
    • IndexError: 当一个序列子集超出范围时触发此异常。(索引会被截取以保证在合理的范围内; 如果索引x不是一个整数, TypeError 异常会被触发)
    • KeyError: 当键值并不存在于图(字典)中,会触发此异常。
    • KeyboardInterrupt: 当用户按下终止键时触发此异常(通常是Ctrl+C或者Delete键)。
    • MemoryError: 当某些操作导致内存耗尽但应能恢复的情况下(通过删除一些对象来释放内存),触发此异常。
    • NameError: 当无法找到对应名字的本地变量或全局变量时,触发此异常。这只针对无效的名字。 附带参数是包含了无法找到的名字的错误信息。
    • NotImplementedError: 这个异常继承于 RuntimeError. 用户定义基类后,抽象方法可以触发这个异常来要求派生类必须实现该抽象方法。
    • OSError: 这个类继承于 EnvironmentError ,主要用于os模块的os.error异常。
    • OverflowError: 当一个算术运算太大导致数值溢出时触发此异常。
    • ReferenceError: weakref.proxy()函数产生一个弱引用代理时,此异常被触发。弱引用代理通常访问一个被引用对象的属性,但这个对象已经被垃圾回收。更多的弱引用信息,请参考weakref模块。
    • RuntimeError: 当一个无法分类的错误发生时,触发该异常。
    • StopIteration: 当一个迭代器的 next() 方法无法获得更多的值时,触发该异常。
    • SyntaxError: 当语法解析器遇到语法错误时触发此异常。
    • SystemError: 当解释程序遇到一个内部错误,但是情况看来可以纠正,不需要放弃退出。辅助参数是一个字符串,标明在更顶层什么出错了。
    • SystemExit: 这个异常被 sys.exit() 函数触发。当这个异常没有被有效处理,Python终止程序并退出;没有堆栈信息打印。如果辅助参数是整数,它表示系统退出状态(和C语言的exit()函数类似);如果它是空则退出状态为0;如果它是其它类型(例如字符串),这个对象会被打印输出,并且退出状态为1。
    • TypeError: 当一个操作或函数调用一个不恰当的对象类型时,触发此异常。附带参数是一个字符串,表明具体的不匹配的类型。
    • UnboundLocalError: 当在一个函数或方法内引用本地变量但变量并没有赋值时,触发此异常。
    • UnicodeDecodeError: 当一个Unicode相关的编码、解码错误发生时,触发此异常。它是ValueError的子类。
    • UnicodeEncodeError: 在文字编码时发生一个Unicode相关的错误则触发此异常。它是UnicodeError的子类。
    • UnicodeError: 在文字解码时发生一个Unicode相关的错误则触发此异常。它是UnicodeError的子类。
    • UnicodeTranslateError: 在转换文字编码时,当一个Unicode相关的错误发生,触发此异常。它是UnicodeError的子类。
    • ValueError: 当一个内建操作或函数接收了参数,参数的类型是对的但值并不符合并且无法匹配一个更加精准的异常(例如:IndexError),触发此异常。
    • WindowsError: 当Windows系统下特定的错误发生或当错误编号无法映射 errno值时,触发此异常。
    • ZeroDivisionError: 当除法或取余操作分母为0时,触发此异常。附带的参数是一个文字信息,标明了运算类型和具体运算数据。

    Tags: ,

  • 24 八 2009 /  我与我车

    俗话说忍无可忍无须再忍,我实在忍受不住了,就在今天,我爆发了,完美的升级了地盘以及制动系统,这下舒服了。

    本次选用的是Stoptech制动系统升级套装,355mm打孔盘,4大活塞卡钳,总体最亮点是轻,很轻。

    为什么选这个呢?个人觉得性价比比较高吧,我的一个朋友从香港运回来一套AP小六活塞的前两周刚装上,价格比这个便宜,只是我觉得在国内很难买到真的AP,正好Stoptech有现货,就直接拿了这套。

    two-big-boxes

    两个大盒子塞满了后备箱,一侧刹车总成装在一个箱子非常专业。

    big-box

    箱子里包括卡钳、刹车盘、钢制刹车管、刹车片以及刹车支架。附送两桶刹车油,我选的是Ferodo DOT 5.1。

    355mm-brake-disk

    355mm打孔盘,方便散热,很轻。

    compare-with-original-disk

    和原厂312mm的盘放在一起比较一下,大了很多。原本选择stoptech 312mm套装的,在朋友的建议下选择了355mm的,一次到位。

    stoptech-brake-1

    大四活塞卡钳,依然很轻。可选红色和黑色,我选择了比较低调的;其它颜色也有,只是需要额外付钱才能拿到,要是不要加钱的话,我会选择黄色!

    stoptech-brake-2

    活塞特写,仔细看是一大一小哦

    original-brake

    再比较一下可怜的原厂刹车分泵

    stoptech-brake-with-box

    再来张远景图

    brake-catch--bracket

    支架,还是很轻

    brake-pads

    附送的刹车片,ST40还是有很多选择的

    brake-pipe

    钢制刹车油管,和其它升级套装不一样的,这套基本上配齐了所有的附件,不需要自己单独选择了,保证了升级的品质

    ferodo-brake-oil

    不是套装附带的,但是老板送的刹车油

    original-brake-system

    开始安装了,原厂刹车的样子,留下美好的回忆吧!

    removed-all

    原厂总成全部拆除的样子,防尘罩为了不蹭新的盘,往后砸了一些(心疼)

    installed

    新刹车装好的样子

    stoptech-front-side-view

    从前面仔细看

    stoptech-back-side-view

    从后面仔细看

    disk-inner-view

    内侧仔细看

    disk-detail-view

    盘子仔细看

    pipe-line-position

    刹车油管安装位,和原厂位置直接吻合

    stoptech-finish-all

    最终完成版,配这个18寸仿passat cc的辁,刚刚好,卡钳前面和侧面都只差一点点,非常之丰满

    finished

    再来一张细节近照

    至此,全部安装完毕,等待片刻,灌好了刹车油以及进行排气,后续就进行了标准的开盘手续。整体感觉从外观到具体使用都是很完美的。目前在磨合期没有敢狠踩,但有助于我从原厂的那个力道适应到更高灵敏度的过程。

    总结,一分钱一分货,如果你希望更加安全,有保证,选择大厂品牌吧。

    Tags: , ,

  • 23 六 2009 /  杂项

    php 5.2.10发布了,喜欢用fpm的朋友又要头痛怎么样打patch了,因为Andrei去忙他更感兴趣的项目去了,最新版本fpm一直维持在0.6.10针对php 5.2.8的版本上。下面介绍如何使用那个patch来升级php 5.2.10

    首先解压php 5.2.10的压缩包到一个目录,然后执行
    gzip -cd php-5.2.8-fpm-0.5.10.diff.gz | patch -d php-5.2.10 -p1
    会输出一些错误,可以忽略这些错误,然后修改php-5.2.10/sapi/cgi/fastcgi.c文件,找到下面的代码,将下面“-”号开头的代码删除。

             if (!tcp) {
                chmod(path, 0777);
    -       } else {
    -           char *ip = getenv("FCGI_WEB_SERVER_ADDRS");
    -           char *cur, *end;
    -           int n;
    -
    -           if (ip) {
    -               ip = strdup(ip);
    -               cur = ip;
    -               n = 0;
    -               while (*cur) {
    -                       if (*cur == ',') n++;
    -                       cur++;
    -               }
    -               allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
    -               n = 0;
    -               cur = ip;
    -               while (cur) {
    -                       end = strchr(cur, ',');
    -                       if (end) {
    -                               *end = 0;
    -                               end++;
    -                       }
    -                       allowed_clients[n] = inet_addr(cur);
    -                       if (allowed_clients[n] == INADDR_NONE) {
    -                                       fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur);
    -                       }
    -                       n++;
    -                       cur = end;
    -               }
    -               allowed_clients[n] = INADDR_NONE;
    -                       free(ip);
    -               }
    }

    然后在php代码的根目录下执行
    ./buildconf --force

    用于清除默认的configure脚本
    然后就可以标准的编译流程了

    ./configure --enable-fastcgi --enable-fpm
    make
    make install

    为什么这样就行了呢?因为patch执行的时候只有两个文件产生了冲突,并且都是跟实际程序没有太大关系的代码(例如一些显示输出),所以,把这些干掉自然就可以正常编译。而buildconf –force可以将配置文件脚本根据当前的代码情况自动生成匹配的新的,这个也适用于你要将一些而外的模块编译到php程序里。在此案例里面就是不用重新修复那个错乱的configure文件了,直接根据当前的情况来生成新的。

    从php-fpm邮件列表来看,php-fpm已经切换成BSD的授权形式了,有位大侠Michael Shadle正在跟php的作者协调,看看能不能将fpm整合到php的标准发行包里面,那样的话就省着每次都做patch了。

    在此呼吁一下,那位有经验在Linux下做C++开发的,是否愿意贡献一下将fpm移植进入php,我可以协助与Michael联系。愿php-fpm蓬勃发展!

    Tags: ,

  • 12 六 2009 /  互联网技术

    通常长连接应用的结构思路网上都有很多介绍,但是很多细节并没有透露。最近实现具体的应用时探索了几点细节,记录下来。主要的问题是客户端浏览器要有实时的消息返回,但通常整个链路上都会出现一些设置问题导致的无法实时返回的情况。

    1、nginx服务器代理模式不会实时返回数据

    因为现在主流的web服务器还没有特别适合事件驱动的,所以长连接部分需要单独写server程序,但我们又希望用统一的80端口来做服务端口,所以我用nignx做了前面的代理,根据规则转发长连接请求到后台的独立服务器上。

    于是问题来了,通过nginx转发并不直接回复给客户端,需要数据传输后断开连接,客户端才能收到返回的所有内容。这是后需要将默认的proxy_pass的buffer关掉,有一个属性是proxy_buffering off;关掉以后nignx会直接返回结果而没有缓存等待所有内容都从后台服务器传送完成才返回给客户端。

    2、Chrome浏览器的实时处理数据机制

    Chrome和其他浏览器不一样,如果你一开始返回一个http头,里面表明有很长的数据需要下载,Chrome没有收到一定量数据前,是不会在浏览器中渲染或者执行这些已经下载的数据的,所以导致你无法通过长连接触发你想触发的javascript或一些你想做的操作。

    解决方案是在后台的服务器上判断如果是Chrome来访则要在内容body里面先输出标准的html头部head和body标签,然后后面跟随至少2048个字节的字符,可以随意,我用点符号来填充,然后才是正式的我要输出的内容。这样Chrome收够了2048字节的内容后就会触发对代码的处理工作,后续的代码也就变成实时触发的效果了。这算是一个针对Chrome的hack吧。

    Tags: , ,