Shell's Home

Nov 27, 2012 - 1 minute read - Comments

异常和错误的几条军规

如果处理不了,就地崩溃,留尸不埋,供后人评价。 偷偷埋尸,100军棍。处理不了偷偷埋尸,拉出去先轮后杀。 忽略错误只有两种合法情况。 逻辑上可以忽略,记log,忽略。 逻辑上期待异常,不记log,忽略。 逻辑上不可以忽略的忽略,100军棍。 逻辑上可以忽略,没有记log,50军棍。 错误在函数间传递的唯一理由,是可以期待别人那里有个错误处理函数,能够对的上这个错误。 没人处理错误的乱传递,20军棍。 该你处理的,处理,不该你处理的,别乱处理。 乱处理错误的,先轮后杀。

Nov 22, 2012 - 1 minute read - Comments

python环境部署

abstract 本文的目的,在于教授使用virtualenv创立python环境,对环境的管理和使用,以及代码和部署的用法范例。在阅读完本文后,你应当可以。 创立,部署,管理virtualenv环境 使用virtualenv环境进行编码 virtualenv环境建立 virtualenv是python的虚环境管理包,他的主要目的是为了隔离环境。其中包含以下两个范畴。 在虚环境中安装包,不需要对系统进行修改,不会对系统造成污染。 在系统中安装的包,不会对虚环境造成污染。这主要是出于版本安全考虑。 因此,virtualenv默认会阻止你使用系统中安装的包。要解决这个问题,需要在建立虚拟环境时指定参数–system-site-packages。 virtualenv的环境可以通过执行virtualenv path加以建立。当建立完成后不可移动,需要一些特殊调整,使用参数–relocatable对此没有帮助。 virtualenv环境的激活和反激活 virtualenv环境是通过替换系统环境变量工作的。在激活后会替换系统的提示符,提示你进入环境。一般我们使用source \$VIRTUALENVPATH/bin/activate来激活。激活后直接执行deactivate反激活。 virtualenv替换系统环境变量的方式是在path前加入virtualenv的bin路径,使自己的python优于系统python执行。同时替换pythonhome,变更lib查找路径。因此,对于某些可以指定pythonhome的应用(例如网络部署),直接指定pythonpath为virtualenv路径即可。 注意,由于virtualenv的工作方式,因此当你执行su/sudo bash后,virtualenv环境都有可能消失,但是提示符仍旧生效。建议通过sudo执行脚本,脚本内进行source比较安全。或者直接sudo目标程序也可以,不要新建上下文。 如果需要保持持续的环境激活,可以将source \$VIRTUALENVPATH/bin/activate加入~/.bashrc。 当virtualenv激活后,后续的pip安装和python使用都会使用virtualenv内的版本。因此下文未经特殊说明,都是指在激活环境后进行操作。 virtualenv环境的管理 主要包括两种手段,安装和删除。一般使用pip install package name进行安装。pip uninstall package name进行删除。 virtualenv环境的保存和恢复 virtualenv环境可以保存和恢复。所谓保存和恢复,是指在安装过包的环境中保存包列表(和具体版本),在未安装(或版本错误)的环境中启用。 一般通过pip freeze > filename进行保存。在目标机器上执行pip install -r filename进行恢复。

Nov 19, 2012 - 1 minute read - Comments

python入门指引

前言 其实我也不知道python怎么入门,由我来写这个真的不是很合适。我学python是直接找了dive into python来看。然后照着写了几个例子。大概两天后,就能磕磕绊绊的上路了。就好像拿筷子,都不记得怎么学会的拿筷子,怎么来教人呢? 不过最近在python-cn的列表里面,我大概连续数周都持续看到“python入门看哪本教程比较好”,实在是不堪其扰。干脆就写个简单的guide,有心的人自己看。没心的——那我也没办法了。 基本知识 首先,你要了解一个事情。很多你不会的东西并不属于python。例如你不知道网络通讯的流程,你不知道文件的权限和打开标志用法,你不知道fork和stdin/stdout的关系。这些python教不会你。如果你缺乏这些和语言/库无关的相关知识,请自行补课。如果你缺乏计算机基础理论,请自行补课。 因此不要随便给我发邮件/留言/咨询,为什么这个问题在python里无法解决。为什么python无法所见即所得,为什么python无法热部署,为什么python无法用于嵌入式开发。在问这个问题之前,请先确认“这是一个python的问题”。例如GIL,或者脑残lambda。如果你不确定,请自己搜索一下相关的文章,确认一下。在提问前,看看“提问的智慧”。如果你确实搜过了,找不到,那就问吧,没办法。 入门 在网络上,python入门的两大基础书籍分别是(后面有朋友补充了一本,我也加上): A Byte of Python 中文版 Dive Into Python 中文版 Learn Python The Hard Way, 2nd Edition 中文版 后面基本就是看python-doc,我推荐你跳过一堆有的没的,直接看Library Reference。python本身就是易读性极强的代码,文档又相当漂亮,内置库又全。大部分情况下,python-doc都应当能解决你的问题。 web web是程序员的一大去向。python程序员入门必须要过的一个框架就是django。不要纠结了,django在python社区中名气太大,用的人太多。因此入门材料是最多的,社区最大,门槛最低。如果你要入门web,必然从django开始。在不熟悉python的情况下,我不推荐你贸然从其他框架开始入门。 当然,如果你已经熟悉python了,考虑入门web框架,可以参考专精一节。 爬虫 python下说到爬虫开发,入门首选Scrapy。原因和上面一样,社区最大,用的人最多。好不好用就见仁见智了。反正我的所有爬虫框架都是用自己基于gevent写的库。 ui python的ui框架也很多,很复杂。同样,如果是入门,我建议从qt的两个框架,pyqt和pyside开始入门。关于这两家的恩怨我就不多废话了。 专精 所谓专精,是指使用python在特定工作上。我们基本分为几个领域。 系统和部署 virtualenv:基本凡是在商用环境中部署的,建议都用这个。可以将python自带在源码里面,避免迁移/集成问题。 python-daemon:写daemon的时候比较方便。 网络 说到网络,基本就是除web外。 twisted:非常强大的网络库,各种协议支持全面,不过reactor模式真是纠结。 gevent:异步协程模式的网络库。 Scapy:强大的网络库,基本啥都能干。 pyzmq:我一直不觉得zeromq是一个mq。我觉得他是一个抽象网络层。 web容器 python web框架的一大特点,是容器/框架/ORM/template可以分开自己玩。 注意,容器和框架是两码事情。容器是python web运行的环境,框架是解析环境的玩意。两者间一般都使用wsgi接口进行连接。这是python的标准做法,fastcgi/scgi也会被转换为wsgi进行连接。但是也不是没有其他选择。一般我们有以下模式: cgi:python-doc中自带了cgi模块。 mod_python:embed in apache。 下面是wsgi接口的容器。wsgi的优点在于我们可以在这些容器上运行任意一款支持wsgi的框架。 flup:支持提供fastcgi, scgi, AJP接口,web server可以用这三种协议进行连接。 Google App Engine:PaaS服务。 Gunicorn:直接提供http服务。 mod_wsgi:使用内部协议和apache集成。 twisted:直接提供http服务。 tornado:直接提供http服务。 uWSGI:使用内部协议和nginx集成。 werkzeug:直接提供http服务。 建议的部署模式是,用apache的,去mode_wsgi。用nginx的,去uwsgi。用GAE的,直接可用。其他,通通转发。

Nov 3, 2012 - 1 minute read - Comments

老大啊,你这是什么鬼名字

sbcl 不知道大家用没用过common lisp,这是一种语言,最早是为了计算理论而生的。这种语言以规模大,难掌握,实现多,标准不统一而著称。 Steel Bank Common Lisp,简称sbcl,就是其中一种实现。他派生于SMUCL,是目前为止我看到的最好的开源实现。反正我在求解N多问题的时候,sbcl在速度和内存占用比上的表现相当抢眼。在lisp系列中称第一,和go这种静态语言相比也不遑多让。 但是每次我看到这个缩写都忍不住想吐槽,这是什么鬼名字啊。SB Common Lisp? debian 大家也许听过,也许没听过,debian社区曾经为了中文名字的事情争吵过。 从我看到的材料上看,很多人对debian的默认念法是——大便。。。 lua 我就不吐槽了,号称屌丝语言。 LZ不哭,站起来lua。 go google的奇葩语言。每次我要查某个用法的时候,都很郁闷。为什么呢?因为几乎所有的网页都命中”go”。 以StartProcess为例,我这里搜素go StartProcess的第一个命中在MSDN,微软有个API就叫StartProcess。再后面就是财经新闻。在很后面才能看到go的API。 etc IT界还有什么奇怪的名字?

Oct 30, 2012 - 1 minute read - Comments

异常之殇

异常之殇 辗转开解 辗转开解(stack unwinding)说的其实是这么一个现象。当执行流从深层向浅层转移时,深层调用所产生的栈上对象(stack object)需要销毁,资源需要释放。对于面对对象语言而言,往往就会执行到析构函数。 辗转开解中的异常 辗转开解真正令人迷惑之处在于,如果在析构函数中发生错误怎么办?在异常处理中发生异常,我们可以继续向上抛出。但是在辗转开解代码中出现异常,上层应当收到两个异常呢?还是一个? 无论是哪种可能,都没有完美自恰的符合直觉,因此这一般是一个未定义的行为。在C++中,进程会整个彻底崩溃掉的。因此,千万不要在析构函数内抛出(或者可能抛出)异常。 如果分离析构和资源销毁 一种做法是,在析构时不做资源销毁,转而提供专门的函数来执行资源销毁过程。析构只处理简单的delete等操作。然而这种做法的杯具在于,你在任何时候,一旦使用对象,都必须使用finally来保证销毁函数的调用。在发生异常时,栈上对象的辗转开解是自动的,析构函数的调用也是自动的,但是销毁函数的调用就是手工的了。 拷贝构造和隐式转换 和构造相反,对于构造函数,我们不能限制异常使用。你必须捕获构造函数的异常。 假如构造函数出了错 普通函数出错,你有两种选择。1. 异常。2. 返回值。构造函数出错,是没有选项2的。因此构造函数凡是出错必定异常。 而如果构造函数可能出错,而你期望捕获他,你就不能栈上构造一个对象出来。因为这会导致栈上对象的作用域被限定在捕获他所用的try块之内。 分离构造的尝试 和析构函数类似,我们可以尝试在构造函数外,提供一个构造函数,来替代构造的初始化过程。这样可以很大程度上保证构造函数不出错。 然而,首先,这样的代码就会变的复杂。每次构造函数完成调用后,都必须调用初始化函数。而且,有两种特殊的构造函数你不可能使用这种方法来解决。 拷贝构造和隐式转换 是的,这两种构造函数分别叫做拷贝构造(copy construct)和隐式转换(implicit casting)。我们举例来说。如果你在函数内建立了一个对象,你希望返回这个对象,怎么做呢?第一个思路是引用返回。不幸的是,要做引用返回,这个对象必须是堆上对象,而非栈上对象。因为栈上对象在返回后会销毁掉。如果要返回栈上对象,唯一靠谱的方案是先将对象复制到堆上,然后再复制到调用者的栈里。 C++中有一类特殊的优化,叫做对象返回优化。当编译器察觉到你需要返回栈上对象时,那么编译器会直接获得调用者栈里的对象地址。这样可以避免两次的拷贝过程。然而,如果没有对象返回优化(或者没有识别出来),那么就需要两次复制以保证正确性。而C++里,默认的复制过程是内存拷贝。 对于很多对象,内存拷贝是错误的行为。例如字符串,一种字符串的加速方法叫做共享内存字符串。两个字符串对象会共享一个内存块,以避免重复内容的开销。直到其中一块需要修改时,复制才真的继续。对于这种情况,直接拷贝会明显的导致错误。因此C++有一种特殊的构造函数,叫做拷贝构造。 在拷贝构造的时候,调用是由C++隐式发生的,你根本没有先构造,再调用的机会和权力。因此,试图分离构造在技术上不可行。 隐式转换是另一种情况。当你传递的参数和实际被赋值对象的类型不一致时(例如调用了某个函数,其参数类型不一致),C++会试图将你的对象转换为目标对象。如果是内部类型,这个被称为内部隐式转换。unsigned char可以被无错的转换为unsigned long,这个大家都知道。但是如果是对象,转换行为就需要由构造函数定义,这个叫做隐式转换构造函数。 另外,隐式转换也是OO中的一大问题。我强烈建议你用explicit禁用所有隐式转换,改为显式转换。这会费一点事,但是却可以避免很多问题。 分离构造/析构的邪恶之处 ZMQ的作者曾经吐槽过这种在构造/析构之外再定义初始化/清除代码的努力。他的观点是,如果万一在构造函数中加入了代码,会引起半构造现象。为了解决这个问题,会使得整个类带上状态。我在上面已经假定这件事情不会发生了,否则代码会更加复杂,问题也更加严重。 二次异常 是的,你不应当在异常处理代码中抛出异常。当然,这里的异常指的是你的异常处理代码不应当发生异常。经过逻辑判定,当前的异常应当由更上层处理的情况不在此列。 如果在异常处理中抛出异常,很可能导致的结果就是异常处理没有完成。而未完成的异常处理会发生什么问题,那只有天晓得。这个在任何带有异常系统的语言中都是成立的。

Oct 29, 2012 - 1 minute read - Comments

面对对象的吐槽——类型之殇

继承之殇 讲继承问题,我们首先得定义什么是继承(inherit),他是用来干吗的。 所谓继承,就是当两种实体,满足其中一种必然全部都满足另一种的定义(is a)。一旦构成继承,可以带来以下好处(简单起见,我们直接就管这俩实体一个叫派生类一个叫父类): 派生类具备父类所有已经实现的方法,毋须再实现一遍——除非需要重写(override)。 派生类可以当作父类使用,凡是使用父类的地方给与派生类也对。 继承的最主要作用,是用于复用(reuse)。 内涵和外延 形式逻辑里面有一句话,内涵越大,外延越小。在继承上,如果我们严格按照定义来做,会发生很反人类的事情。因为类的定义是依赖于内涵的, 我们还是看平行四边形,长方形和正方形的例子。我们用两边长度,夹角来定义平行四边形。然后如何定义长方形?夹角为pi/2。然后如何定义正方形?两边长度相当。 不知道你是否看出了问题。是的,按照正统来定义,数据的约束只会越来越多。因为派生类必须是(ISA)父类,因此父类的约束必须全部满足。我们接着上面的例子,我们为平行四边形定义一个方法,设定夹角大小。那么在长方形中,这个方法如何处理?一旦用户调用方法设定夹角大小,必然会破坏长方形定义,因此这个方法只能重写抛错。 为什么?从逻辑的本源来说,平行四边形是“两组对边分别平行”,并没有说夹角的事情。到长方形的时候才说,长方形是夹角为90度的平行四边形。显然,长方形是不能设定夹角的。因此,我们要么承认,不是每个平行四边形都可以设定夹角的,例如长方形不行。要么承认,每个平行四边形都可以设定夹角,长方形不是平行四边形。显然,后者违背逻辑,我们只能得出结论,不是每个平行四边形都可以设定夹角。 同样,正方形的例子也说明,不是每个平行四边形都可以设定两个分离的边长。如果以此标准来定义类,那么必然得到的是正确而无用的逻辑玩具。平行四边形没有夹角,我们就不能定义面积计算的函数,也不能——基本什么都不可以。更过分的是,我们还不能定义两个分离的边长,因为定义并没有告诉我们,边长一定不等。照此下去,我们除了一个空空荡荡的“平行四边形”这个名字外,什么都定义不下去。 为了解决这个问题,实践中,我们采取的都是,平行四边形是可以设定夹角的,然后对特例做抛错处理。这其实在本质上就违背了继承的原初意义。 继承和聚合 继承的另一个容易混淆的地方,就是分不清继承和聚合。 其实从逻辑上说。继承和聚合根本就不是一回事情。例如你有(have a)一条狗,你可以让狗做任何狗可以做的事情,例如追猎物。我们可以说,你可以做的事情和狗没有区别,所以——你就是(ISA)一条狗?! 傻子都不会弄错其中的区别! 我们说,如果一个东西看起来像鸭子,叫起来像鸭子,走起路来像鸭子,我们就可以当他是一只鸭子,说的是弱类型语言。而且我们只能认为,我们不知道那个东西是什么(这是弱类型的特点),总之可以当他是一只鸭子用。但是这不代表那个东西就是一只鸭子,他也可以是鸭子的代理人,或者拥有一只鸭子。在静态类型语言中,为了复用就不管三七二十一,直接声明PNG图像是一种BMP图像的——这绝对是逻辑上错误的行为。 然而,你自己数数你在代码里面犯过多少次错? 多重继承 继承本身的问题我们先不说,我们再说一个很常见的问题——多重继承。 既然我们说,只要一种满足ISA谓词判定,就可以认为是继承。那么理论上,我们就不能否决双重继承。例如我们定义了平行四边形,又定义了中心对称图形。那么长方形就同时是(ISA)这两者。从逻辑关系上,我们说长方形可以合法的继承两者。 但是如果我们真的在程序内设定将长方形继承两者,马上会引起一连串的问题。 当多重继承发生冲突时 首先第一个是继承冲突。即当两个父类都具备同一个方法的时候,对派生类做方法调用会发生什么行为? 肯定不能只调用一个,这会因此另一个父类的方法间发生内在不一致。这违背了继承的好处2。 也不能两个都调用。两者的先后次序可能引发逻辑问题,因此先调用谁都是错误的。而且函数还有返回值问题——你返回谁的返回值呢?如果多值返回合并,这和函数原始的定义又发生了悖离,从而又违背了继承的好处2。 因此,我们只能宣布这是个错误。 既然是个错误,鉴于类间函数可能存在的内在联系,其他继承的函数也未必能够正常使用。 你看,明明是合法的多重继承,居然造成了不可复用的结果。这就是继承冲突。 菱形继承 如果说继承冲突还是一个比较好考虑的问题的话,菱形继承就是一个让人吐血的东西了。 所谓菱形继承,就是两个父类继承同一个基类。在这种情况下,对父类的调用会间接转到基类上。那么,基类的函数会调用几次呢? 继承冲突的几种解法 所有冲突的函数,父类必须都无实现。 不得多重继承。这是很扯淡的,不过也是大多数时候的做法。我的编程指南之一就是——在C++中,任何时候都不要使用多重继承。 使用其中一者。python是个典型的使用其中一者的例子,具体使用的按照继承编写顺序展开成MRO次序决定。然而这直接违背了继承类是(ISA)父类的定义。因此不要以为在python中,继承后总是没问题的。有的时候可能会出现继承后不能正常工作的情况。 强制用户解决。要求用户必须人工定义函数,解决继承冲突的问题。从逻辑上说,如果用户定义的函数可以同时兼容于两个父类,就可以彻底化解多重继承冲突问题。然而杯具的是,很多时候在逻辑上,继承冲突是无解的。 区分接口和继承 父类没有实现冲突的函数,那么派生类中就不必纠结于调用谁的问题了。但是这引发了另一个问题——这就无法复用了。作为这一解法的极限,java不允许多重继承——除非继承的父类都是没有实现的类。这其实不是继承,而是实现(implement)接口(interface)。 接口编程是一个很有道理的东西,COM里面大量着重于接口。但是接口也有自己扯淡的地方——接口是一个编写期的东西,他最大的用途就是编译期类型检查。接口并不能复用(reuse)代码。如果你有一个接口,叫做平行四边形。里面有个方法,用于计算平行四边形面积。然后你实现了长方形和正方形——那么杯具来了,你需要在两个里面通通实现一遍这个方法,即使他们基本没区别。 当然,接口本身的好坏各有评价。你看,接口的唯一作用,就是声明类提供了某些函数。当我们对方法传入一个新的类的时候,我们必须将新的类也实现一下接口——哪怕这个类其实已经实现了这些方法。只要不实现接口,方法就不认可。这是强制编译器类型检查(静态类型语言)的基础。因此一般来说,静态类型语言,使用接口。动态类型语言,duck typing。

Oct 28, 2012 - 1 minute read - Comments

高考和大学的选择

背景 最近很多家长在为了高考的事情争。非京籍家长要求北京市教委给予外地孩子公平待遇,京籍家长认为北京本地教育资源有限,应维持现有状态。 另外,我在weibo上和一个交大的特招生吵,他认为特招生deserve大学(原话),我认为归根到底是个利益问题。 OK,以上是背景。 大学是一个什么? 中国的大学扩招比例是所罕见,其中有一个很大的因素是因为各种家长都认为孩子应当上大学。上过大学的孩子就跳龙门了。在我的观点来看(当然,我也有很多佐证),上大学不是跳龙门,谁上什么大学才是。我的一位朋友,是从偏远的农村来的,他们那里有个有趣的现象。凡是没上大学,高中毕业就工作的,家里多半都盖起了小楼,娶了媳妇,在本地工作。上了普通大学的,一般都还住在很旧的老房子里面,孩子在远方的城市,没结婚,刚刚还完,或者还在还学校的贷款。而上了一流大学的,则家里又比较富足,有很大一部分家长直接去了孩子所在的城市,很可能这些城市甚至不在中国。最后一种是否幸福,如人饮水冷暖自知。但是我要说的是,为什么会产生这样的分层变化? 关键是大学是什么样的一个东西。 我们为大学付钱,大学给我们各种资源。当然,好不好,值不值,就是一个很关键的问题。很多大学并没有资源,或者说没有足够的资源。这样的大学就是来赚你的钱的。中国人千年以来都认为,学而优则仕,念书是能当官的。于是再穷不能穷孩子,都变着态的往大学送。这种人的钱不赚赚谁的?自然,孩子没有得到好的教育,工资和普通高中生拉不开差距,家里又很是交了一笔学费,不穷你穷谁? 这年头家长也不都是傻子,我们从来不为进入这种大学而争论。问题是,那些好的,能够给你资源的学校,谁在进?谁应当进? 谁进大学? 首先你应当明白,大学并不是象牙塔,他不天然是为了让好的学生变得更强而出现的。大学的出现,是他的设立者为了他的理想而建的。如果他的理想碰巧是,让好的学生变的更强。那么,是的,这也是一种可能。但是你应当明白,另一种可能性是,为各种有钱人世家教育子女,让他们的子女比别人的子女更强。我得说,这也是一个可能。 那么中国的大学是什么? 刚刚我们说了,一种大学是赚钱。我们从不争论谁应当进去挨一刀。至于那些能带给你什么的大学,一般都是国家掌握的。这些大学创立的目标是什么,他们选学生的标准就是什么。国家运作这些大学是为了什么呢? 还是赚钱。中国的大学培养了相当大的一批高级产业工人,这是个不争的事实。有产业工人才有GDP啊。既然是培养产业工人的,那么招人的标准就相当明白——增加产业工人培养的成功率。一般来说,好的学生比较容易培养成优秀的产业工人。但是这不是正向相关的,里面总要附加点什么。首先,政治必须正确。政治不正确的学生培养出来是危险品。其次,学生要足够好,不够好的不培养难度太高。于是你就知道高考是怎么一回事了。首先,你必须政治正确,否则根本不会有高考机会。其次,考试。 谁应当进大学? 当然,我们是没有办法对国家施加影响力的。我们只是从理论的角度说。如果全民可以投票,来决定进入大学的制度,谁应当进去? 当然你也应该想的到,谁应当进大学是个政治问题,而不是技术问题。本质上,决定谁进大学就是决定谁在将来拥有利益。这是一个利益之争,永远是。我和那位交大的特招吵,就是因为他觉得特招理所应当进大学,因为他们deserve。而且他不觉得这和利益有什么关系。我不觉得谁是理所应当进入大学的,大学不是赛跑,跑赢拿奖品。大学不是养鸡场,养出一批换一批。所以我觉得以考试为基础来决定谁进大学本身就是个问题,高考有问题,特招当然也有问题。 但是我们没法脱离高考,你们都知道为什么。既然谁进大学是个政治问题,那么一种无论听起来多么合理,却看起来不见得公平,操作起来更可能有黑幕的方案,是绝对不可能上的了台面的。而目前,问所有人,觉得还算公平的方案,就是高考,大家一碗水端平。即使是高考这么看似公平的方案,也有无数不公平的细节在争吵中。特招生多了,平衡发展的学生家长就要有意见。取消特招了,偏科生家长就要有意见。开放对地区的人数限制,招生比例高的城市家长有意见。不开放,外地家长有意见。你知道的——无论社会民主还是不民主,这是永远的利益之争。所谓民不民主,只是这个问题是由大家投票解决,还是领导拍板解决。 关于地区之争,我首先引述一篇文章民主的细节 – 谁有特权上大学,文章需要翻墙,我引述如下。 看了刘瑜《民主的细节》,我没觉得美国像天堂,但中国真的很像个炼狱。 一个简单的例子。 刘瑜引用罗尔斯《正义论》的解释说:只有当你不知道自己可能是谁时,才能想清楚什么是正义。“他有一个术语,叫“无知之幕”,也就是一个人在对自己的社会处境暂时失明的情形。一个站在“无知之幕”后面的人,既可能是比尔盖茨,也可能是一个非洲饥民。如果你觉得正义就是杀光富人瓜分他的财产,万一“无知之幕”一拉开,发现自己就是比尔盖茨,恐怕你会后悔得一头撞死。如果你觉得正义就是WINDOWS 2000卖5000美元一套,万一“无知之幕”一拉开,发现自己其实是非洲饥民,估计也要捶胸顿足。” 然后,她举了美国人关于“谁有特权上大学”的争论。自60年代的平权运动始,许多人主张给黑人和妇女在入学上优惠,以补偿之前遭遇的歧视,叫做“补偿性正义原则”;但是矫枉过正的结果,产生“逆向歧视”,70年代中,一个叫巴克的白人学生不满自己在考大学上屡屡败给各方面都比自己差的黑人学生,上诉最高法院,法院裁定对黑人学生实行定额制是违宪的,但原则上仍支持平权行动,这个叫“程序性正义原则”。后来的40年,美国人民一直在如何协调这两种正义间苦苦挣扎与思索……中国呢? “好了,终于可以回到咱们开头提的那个问题了――来自火星的你,被扔到大城市、内地、边疆的可能性各三分之一,你会如何设计高考分数线方案? 你可能会说:三个地方分数线一样嘛!大家公平竞争嘛! 你也可能会说:让边区分数线低一点,其他两个地方一样,因为那些地区贫穷,教育条件有限,人家北京上海的孩子用电脑打字,俺们这里还是凿壁借光呢。 你还可能会说:我选择让北京上海分数线低一点,其他两个地方一样。因为……因为……咦? 你们地球夏天真热啊? 我们知道,这三种选择,第一种叫“程序性正义原则”;第二种叫“补偿性正义原则”;第三种,姑且称之为“夏天总是很热”原则吧。” 元芳你怎么看? 大学值不值得进? 首先我给光知道赚钱的大学定个性吧。这种大学您就别去了,去了等于白去。 其次,对于指望搞研究的,真的对学术有兴趣的。我的建议是你尽快找好老婆,尽快走,出国读研究生。中国也是干活,外国也是干活。人家待遇比中国高不说,还没P事,能让你专心做研究。国内但凡是个院校都是一堆P事,搞行政的时间长过做学问的时间。 最后,您要是指望出人头地的——那就吵吧。。。 我的立场? 我其实是特招的受益者,当年我是物理竞赛的二等奖。但是,那毕竟是过去了。现在我物理方程都不记得几个了,要做计算更是要依赖程序了。而且——我也不会再高考了。 所以其实个我对高考的立场就是个无知之幕——谁知道将来会生儿子女儿,是偏文科还是理科。我连将来会不会在中国,想不想生都不知道呢。 所以我在偏科问题上的立场是随大流的,一般来说,强到特招的概率总比平均分数高的概率来的低吧。至于地区之争,我得说,原则上我支持向贫困地区倾斜。但是行动上支持北京和上海保持本地人低分数线。 听起来很悖论,但是这是诚实的想法。

Oct 25, 2012 - 1 minute read - Comments

cython编译细节

两点简述: 可以使用cython –embed来编译一个pyx,生成带main的代码,然后用gcc直接编译过去。大概样例是这样的: cython –embed $^ gcc $(shell python-config –includes) $(shell python-config –libs) -O2 -o $@ $^ pyx的文件名会被转换为变量,所以所有在变量中不应当出现的符号也别出现,例如-。

Oct 23, 2012 - 1 minute read - Comments

pycon2012

今天第一天在大型会议上演讲,其实挺紧张的。不过还不错,虽然临场反应并不热烈,但是至少不冷场。下面是我今天看到内容的回忆,有些印象不神,记得不清楚了。 第一天上午 视频播放 上来先是sting先给我们放了一堆视频,我基本啥都没记住。就记住一个在日本的pythoner说教孩子编程时大家的评语了——python穷三代,编程毁一生。我后面接的是,用scheme子子孙孙都完了。 python产品构建和发布指南 沈游侠的主题,彻底干货。基本要点就是利用cython和pypy来编译类python语言,变成C语言代码。这样不但速度快,而且C代码都是可以跨平台的。后面又列举了如何用cython和pypy来编译库。这样基本可以完成python到多数平台的移植。 我做了一下简单测试。cython对速度的增加主要是静态类型编译,如果保持代码不动,速度反而会略微下降。因此在速度提升上,作用并不如想像中那么明显。但是在跨平台上,效果就非常好。rpython则完全相反,经过rpython编译的代码,在基本不修改的情况下(当然,前提是你需要符合rpython),执行比C还快。 不过游侠在后面的答疑中也说了,pypy的rpython编译把握难度比较高,不建议在产品中使用。 另外,他后面也提了溜宝的例子,在python和js之间可以远过程调用,还可以回调。熟悉http的应该可以听出来,这个在现在浏览器中必然是要用到long pull技术的。因此底层框架不肖说,必然是Eurasia。 让程序运行更快 我们几个都在说,土豆的一贯风格是分享内容是和技术有关的干货,但是都和python不搭边。最多在最后说一句,这个技术在我们这里是利用python做的。上次黄东的演讲就是,讲如何算流量带宽费,最后来一句,这个是python实现的。这次李小红的分享也是,很技术,但是和python没啥关系。讲到一半还来了一句,“我对python不熟悉,前几天特意看了一下,dict是利用开放地址法实现而不是开链实现的,这让我对python顿时有了信心”。微薄上无数吐槽高级黑啊。 土豆的分享其实很简单,核心就是如何通过代理让网站的响应速度更快。干货是干货,但是不是非常熟悉http协议,能够将http本身优化到相当程度的,听了等于白听。因为上面讲的大部分,都是内存命中和交换,磁盘写出,cpu调度,poll和epoll内核模式差异之类的话题。在python下面,poll和epoll基本都看不出差别,大部分优化都围绕着模式打转。研究这种命中技巧不是南辕北辙么? 但是这不表示这个主题没用,只是如果你不把其他方面的问题解决的很彻底,先没头没脑在CPU和内存缓存命中上下功夫,多半是做不过别人的。 第一天下午 OpenERP 即将推出的第 7 版的功能和新的编程框架介绍 演讲者是个法国人,中文相当不错。不过和Thomas比起来还是差点。旁边的老外哥们说,那是因为Thomas有个好中国老婆。 基本是广告。除了让我们体验了一把openerp的风格外,啥都没看着。不过openerp看起来确实够屌的,直接去下一个插件,应用,然后就直接换掉了语言。这基本和php差不多。还有一堆的良好的交互特性,看起来非常像应用。此外,啥技术都没有。 元编程在 Redis ORM 中的应用 我自己的题目,会场反应并不很热烈。总共两个选项,我问认为是1的举手,几个。认为2的举手,几个。剩下的是啥? 其实元编程本身就不好讲,这个题目我写完文档算了一下,大概1个小时到一个半小时。问题是我问sting多要点时间,没有。好容易给我加到45分钟。我对着文档左砍右砍,还是紧紧张张的25分钟讲完。要在30分钟出头讲完整个题目,也难怪听众反应不良。 具体我也就不展开了,希望看到的可以看我的slide。另外我说一下,这个slide也是我用python做的。 用 Tornado 开发 RESTful API 应用 其实以这个应用而言,是适合GAE的项目。不过飞龙只是借这个题目讲Tornado而已。 阿里云之移动开发者上云 纯粹广告。不过既然是lighting topic,也不算太难受。我也顺便看了一下阿里云的架构。不过主讲完全没讲到要点,他们到底是卖IaaS业务,还是卖PaaS业务,还是云存储,还是三者都有?另外,用IaaS来做PaaS的可伸缩?我还真不觉得这是个好主意。。。 Python如何帮助「逆转三国」获得成功 广告中的广告。今天唯一一个妹纸上场的主题,我还在想,终于有妹纸上去做分享了,还是个美女。结果介绍完了心里就凉了半截——市场总监,这姐们是个非技术的角色。演讲的主要内容是,python很好,python没出过乱子。完了,总共15分钟不到,我连拍第二张照片的机会都没有。其余时间全在说游戏是如何成功,左右还有海报助阵。最后还出来一个美女发传单。 最后主办方出来道歉,他们也以为这个topic是正规演讲,没想到讲成了lighting topic。 网页游戏的跨界开发 董诣的题目,主要讲他如何训练公司的策划使用python。他用的方法基本就是元编程的路数。 策划将配置写入excel,然后他们的程序读取excel,写出一个python的文件,再由服务器加载。这是典型的字符处理型元编程的例子。早知道他们这么用,我满可以顺手拿来举例的。 最后他的例子倒是让我们吐槽了一把。print后面可以不加空格,这是他们公司美工教的。 实战游戏客户端 林伟每年来都是带来大量干货。今年他是特别从北京飞过来,在演讲前刚刚到场。 他的题目是用python做客户端,并不是很好讲。因为python做游戏客户端不是很多。他举了一个pygame的例子,超级玛丽的企鹅复刻版,玩的挺欢乐的。 后面他大概讲解了一下游戏界面编程的几代模式变化。不过我印象最深的还是说到flash在苹果上。后面他运行flash的那个模拟的时候,我彻底吓一跳。我偷偷和沈游侠说,林伟说的完全没错,乔帮主抹黑flash完全是为了抢app的地位。 大家可以想象一下,如果flash拿到了硬件驱动加速会如何?Apple Store上的程序还有谁会花钱?都直接用网页跑一个Flash游戏就直接玩了。PC上能跑的,在苹果上自然也能跑,效果还不差。那还用Objective C做什么?只有性能要求特别高的才会用到。如果不需要Objective C,那Apple Store还怎么赚钱?从Flash能够做到这点,还有Adobe的战略布局,以及Apple Store目前的情况。我们多半可以得出这么个结论,苹果抹黑Flash的主要目地是将Flash踢出移动平台。而只有将Flash踢出了移动平台,才能保护移动设备开发市场的封闭性,从而从中牟利。 另外,他讲到的FlashCC也很有意思。在一个语言内调用其他语言,这非常有利于Flash的开发。不过后面林伟的一句口误让全场都笑了。他说:“我今天来就是告诉大家,从今以后,大家可以用Flash开发python程序了。”得,又是一堆高级黑评价。 第二天上午 网游开发中的 Python 组件 赖总的topic,基本讲的其实是模式。 对我来说其实也挺有用的,尤其是关于对象可调用方法的那个idea。写程序到了一定程度,实现已经不是问题。只要有明确的实现方法,你给足够的时间干,肯定是干的出的。问题是思路,也就是idea。一个好的思路往往是经过很久的总结,在实践中不停摔倒,才能真正用上去。 另外,最后的吐槽,其实是自行实现语法,或者至少是语法糖。我和赖总说,scheme其实很容易嵌入,而且很容易实现这样的要求——lisp类语言的宏天下闻名。赖总在研究的是基于python自己的Parser的方案,我回头有空也看一下。 Python in Gentoo Linux Patrick Lauer的主题,主要是讲了Gentoo下面如何使用python,每个版本的python在gentoo下面的支持情况如何。按照数据来看,python3的支持接近完成了。而pypy大概只有2/3的支持比例。

Oct 18, 2012 - 1 minute read - Comments

没想法

前两天面了一个同学,是我在交大的学弟。平时印象挺不错,用过的技术也挺多的,和老板商量一下,就面试看看吧。 结果不能算糟,但是也谈不上多好。主要是,这同学没想法。 不知道和没想法 老板最恨的一件事情,就是在问你一个问题的时候,你手一滩,说”我不知道“。其实严格来说,他并不介意你说”我不知道“(I don’t know),但是绝对不要说“我没想法”(I have no idea)。 拿面试时候的例子来说吧。那位同学讲了一个实验室里面的项目,用web来控制小车。当然,那是个没做完的项目,有什么问题也不是值得奇怪的事情。我们开始的时候问了几个问题,感觉还可以。事情是从我随口的一个问题开始的:”如果两个人同时操作,会发生什么事情?“ 两个人同时操作在设计上是不允许的,完备的系统可以通过一些方法来排除这种可能。例如,见到第二个cookie就给一个空页面回去。项目没做完,没屏蔽掉第二个人,也不是什么值得奇怪的事情。但是我想知道的是,对于这么一个未定义的事情,被面试的人是如何分析的。 按照正常流程来说,分析这个问题首先需要知道基本的工作原理,然后拆分工作流程,最后分析,如果两个指令同时到达,会发生什么现象。问题是,该同学阻塞了半天,啥都没干。我和老板询问了整个系统工作的原理,发现他对基本原理都是了解的。我们按照他所说的原理,推断出了两个人同时操作会发生的结果。当然,是否正确,谁也不知道。但是我们的结论是,他在具备所有推论需要的知识的情况下,没有做出任何推论和结果。 这是一个很扣分的事。 不知道 所谓不知道,是指你的知识(knowledge)不足以解答当前的问题。例如,对于非程序员,我问你,python中用于逐次返回数据的关键字叫什么。你手一摊,告诉我,我不知道。这是因为你压根没学过python,当然不知道yield。 不知道并不是值得羞耻的事情,无论多强的程序员,总有什么东西是他不知道的。新的语法,新的框架,还有我们没听说过的技术。作为程序员,什么都知道反而是一件无比诡异的事情。 没想法 很多时候,没想法是因为不知道。例如,假定你对股票市场的工作机理一无所知,尽管你完全可以理解,作为正常人类都是希望高买低卖。但是当我问你,股票市场表现如何的时候,你也只能手一摊,我一点想法也没有。这不仅仅是你不知道,而且你都不知道该如何去分析这个问题。 因此正常程序员见到一个不知道的系统,第一个问题十有八九是,这系统干什么的。第二个问题就是,这系统怎么工作的。当你知道了系统的大致工作机理,就会想出如何分析这个系统的方法。 例如,我们有一个网络系统,老板说网页访问慢。元芳你怎么看? 这后面没什么天大的秘密。我们只要照着网页访问的流程来看就好。 DNS解析 tcp连接 http请求 http返回 DOM解析 js执行 网页慢,首先分析最慢的地方在哪里。这里的每一步,都是能够计量的。我们再假设,我们发现最慢的是http请求和返回,那么我们基本就把问题定位在了服务器或者网络容量达到极限。那我们又如何分析是对方服务器太慢还是我们自己网络太慢呢? 只要你没傻,都应该想的到,最简单的方法就是同时开一个比这个页面快的多的系统,一个不会慢的服务器。最合适的是google和baidu的首页。如果还是慢,那就是我们的网络问题。如果快了,就是对方服务器到极限了。 做出这个分析,并不需要什么惊人的知识,也不需要你有足够的经验。当然,经验可以帮助你快速的排查问题,当出现某些现象的时候,别人还在做诊断,你就可以直接做定性测试和结果了。 你可以不知道,不可以没想法 作为程序员,我可以接受你告诉我,你不知道。但是一般我不能接受你告诉我,你没想法,尤其是在一些情况很明白的核心问题上。如果这是一个很困难的问题,没想法也不奇怪。有些很妖怪的问题,例如为什么我们的系统在人少的时候OK,人多了就挂了,再多又没事了。通常的性能计数又没异常,问题随机出现,无法复现。像这种妖异的问题,我没想法,你没想法,我问别人也没想法。但是如果我问你,网页为什么慢,你告诉我,没想法。或者更夸张的,在不经过相关测试的情况下,随便看了看现象就告诉我——这是我们的网络带宽不够大——你丫当我村干部糊弄呐! 没想法表示你对这个系统没办法。你没办法做一些事,在可预期的成本和时间内解决问题。你能做的就是去网络上找出过这个问题的人,他们的解决方案,然后照做。coolshell管这个叫做散弹枪式编程,我管这个叫做博彩。散弹枪不是一个很坏的主意,对于一些你不关心又需要很快解决的问题,你可以散弹枪一把。但是如果你在头三个方案内都没解决问题的话,你就可以停手了——后续方案能解决问题的概率和头三个没有太大分别。 有的时候,散弹枪是一个非常糟糕的做法。例如我们上面那个——网络带宽不够大——的例子,你很容易在网络上看到这个解答,但是往往这不是正确的答案。我是说,很多人确实是因为网络带宽不够,所以出现了网页缓慢。但是网页缓慢的原因,还有一个是因为延迟和丢包率太高。而增加带宽可解决不了延迟和丢包率。甚至相反。我们可以想像这么一个可怜的例子。当技术瞎猜到——是你的带宽不足——时,老板就会对行政说,去给我换一个给力的带宽。于是行政要升级带宽——又要控制成本,十有八九,他们会找上一家小ISP。ISP的性价比非常可观,行政和老板都很满意。唯一的问题,是他们的延迟和丢包率比上一家更加糟糕。 你看,散弹枪不但没打中目标,还使得情况更加糟糕了。 类似的问题还出现在大型电商系统的架构上。如果架构师和SA的答案永远是——硬件不给力,你需要好好考虑一下,真的是硬件不给力,还是这只是一个拖延的借口。如果架构不合适,当规模达到一定量级后,无论你再堆多少的硬件,可支撑用户数都不会有太高的提升。