流水笔记

面向免费零食和饮料的编程

又回学校了

真快啊真快啊,转眼间的事情

昨天坐了一整天的各种交通工具,回到宿舍都虚了,晚上吃饭很有想吐的感觉,于是草草吃了点就回去了。自行车又没气了,看来还真的是一个学期就必须打一次气的。回去以后把风扇插插洗洗(原来把内壳拿出的方法不是压扁内壳,而是拉开外壳),然后拧螺母的时候又发现死活拧不紧去,手都快拧滑的时候才想到是不是应该把螺母翻个个再拧呢,于是发现果然是这样的。

然后爸打电话过来说我没给他改程序,因为他电脑里面的程序还是错的,然后我敏锐地指出他当时只是拷到U盘,然后就匆匆赶去打麻将了,一说果然是。

然后睡觉,睡着睡着突然发现不太对头,匆匆跑厕所,回过头一想似乎果然是每次吃饭吃到想吐总是有点什么问题的。还好之后吃了点药就一夜安宁了。然后早上起来又发现全身乏力,也不知道是拉肚子的原因还是发烧,更悲剧的是发现我的钥匙不见了。四处找了一会没找到遂决定睡觉,这个很好,睡醒了以后虽然还是全身无力,但至少想到钥匙可能放在哪里了,一找,果然在蚊帐下面。

于是去吃午饭,依然没有食欲,于是想喝粥,紫米粥是肯定要的,但是似乎不够吃,看到绿豆粥上面似乎隐隐约约飘着点肉,大喜,又要了一碗。结帐的时候发现一共才1.1块,想怎么可能有肉呢???噼里啪啦灌完紫米粥以后试了一口绿豆粥,发现不仅没有肉,而且超难喝。又试了一口,依然很难喝,果断不喝,直接拿到回收处。

然后去买网线,C楼网线质量虽然差,但想着好像也没有别的地方能买,于是也只好委屈一下了,哪知十块钱的网线买回来刚插上就断了卡位的那个透明状物体,真是气死我也,于是继续睡觉,不开风扇憋了一身汗以后醒来发现似乎还好,腰不酸了,背也不痛了,上楼也倍儿有劲。于是开始改代码,改吧改吧发现是不是应该写点什么东西先,于是就开始写了。

另,发现似乎实验室有钱发了,账户里面有了转账记录,虽然还看不到钱是多少,但依然我心甚慰——终于有钱了

[仙剑]图片系列全部解析完成

其实是很久之前的事情了,一直没时间写。现在除了145号地图(似乎是锁妖塔某层)有问题以外其他都已经解析出来了。找个时间调一下145就好了。

另外速度问题现在先不处理了,没什么方法。

最后是仙灵岛的地图,原图很大,这里是缩小了的。

回到家了

几乎是坐了两天整,累死了。昨天回家以后从七点一直睡到几天早上五点。

翻译的一篇文章

一篇关于Python速度的文章,感觉写的还是不错的。一时兴起,就翻译了一下,不过翻译水平自然是很差了,所以看不懂的话就看原文

Python的速度

经常会有很多人担心Python写的程序会存在性能上的问题。是不是说使用Python就意味着性能上会有不可接受的损失呢?一些人会往往会不假思索地给出结论:“Python是解释性的脚本语言啊,解释性脚本语言都是非常慢的!”然而另外一些人经过实际测试以后发现Python其实并不慢。当然,某些时候可能是因为你恰好有一个跑的非常慢的程序。

速度对于程序来说是不是重要吗?

有些人可能会盲目地追求所谓的速度;在他们看来,像C这样的语言在很多场景下能够提供更好的运行速度,所以他们会觉得不管什么场合C都是一个更好的选择。但是另外一些人可能会觉得开发速度才是更重要的,所以即便实在那些Python运行效率不那么高的应用里面,他们还是会选择Python。而且这些人往往也会惊奇地发现Python代码的执行速度还是可以接受的,甚至某些时候在开发时间差不多的情况下Python的代码甚至会比C/C++要来的快(译者:本来还觉得挺好的,这么一说就没什么意思了。。。)。

通常来说,绝对的速度并不是最重要的,你应该考虑的是一个可接受的执行速度。优化地太多反而是对资源(你的时间或者金钱)的一种浪费。

提高性能和可伸缩性的技术

下面是一些提高内存使用、速度和可扩展性等方面性能的编码原则:

使用更好的算法或者更快的工具

  • 测试从属关系的时候,使用set和dictionary(O(1)的时间复杂度)比普通序列(O(n)的时间复杂度)要快得多。比如说对于“a in b”这样的语句,b应该是set或者dictionary,而不是list或者tuple。
  • 字符串连接用”.join(seq) 的方式会更好(O(n)的过程)。相反,如果使用“+”或者“+=”操作符的话复杂度是O(n^2)的,因为在这个过程中的每一步都要生成一个新的字符串。CPython 2.4翻译器在一定程度上优化了这个过程,但是”.join(seq) 仍然是最好的方式。
  • 很多工具都有链表(list)形式或者迭代器(iterator)形式(range和xrange,map和itertools.imap,list comprehensionsgenerator expressions,dict.items和dict.iteritems)。一般情况下,迭代器形式对内存要求更低而且有更多的可伸缩性。如果并不需要一个真正的list的话,迭代器形式是一个更好的选择。
  • 很多核心模块都是用优化过的C来写的。利用这些模块可以让程序性能有很大的提升。这些模块包括所有的内置数据类型(list,tuple,set和dictionary)和像array、itertools、collections.deque这样的扩展模块。
  • 类似的,内置函数也会比手工构建的函数要快,比如map(operator.add, v1, v2)就比map(lambda x,y: x+y, v1, v2)快。
  • list结构在处理定长数组或者变长的栈的时候效率较高。然而当涉及到队列的pop操作或者插入操作的时候,使用collections.deque()更好,因为它避免了每次插入或者删除的时候需要重建数组的过程,所以它的时间复杂度将由O(n)提高到O(1)。
  • 自定义排序的时候,使用Python2.4的key=或者传统的修饰器效率更高,因为它们的实现只需要对每个元素调用一次key函数。而不像cmp=那样每个元素都要调用很多次。比如sort(key=str.lower) 要比sort(cmp=lambda a,b: cmp(a.lower(), b.lower()))快。另见TimeComplexity

利用解释器优化

  • 在函数里面,局部变量的访问速度要比全局变量、内置数据和属性查找快。所以有时候在内部循环里面把变量局部化是值得的。 比如random.shuffle()函数使用了random=self.random进行局部化,节省了每次循环都要查表(在self中查找random)的过程。当然在循环外部这样做的话就不太值得了。
  • 上一个建议是一个把常量表达式提出循环的通用规则。类似地,常量的展开也应该手工地做,比如说在循环里面应该把x=1+2替换成x=3。
  • 函数调用开销要比其他的操作大。因此有时候应该在一些关键的循环里面应该把函数内联(inline)。
  • list comprehensions要比for循环稍微快一点(除非你不想要结果)。
  • 从Python2.3开始,解释器对while 1进行了优化,相比起while True而言,它在循环判断的时候只有一次跳转。因此在一些关键的场景下可以使用while 1来替代while True,虽然这有可能会降低程序的可读性。
  • 混合赋值(x, y=a, b)比独立赋值要慢(x = a; y = b)。当然,通过混合赋值来交换(x, y=y, x)还是通过临时变量交换(t = x; x = y; y = t)要快。
  • 链式比较比用and操作符要快,因此应该把x < y and y < z写成x < y < z。
  • 另外还有一些快速的实现应该只在最需要的程序里面使用。比如果用not not x会比bool(x)快。

利用诊断工具

  • hotshot和profile模块可以用来定位性能瓶颈所在,profile工具还能识别消耗在Python代码上的时间和消耗在C代码上的时间。
  • timeit模块提供一个分析不同实现的及时的性能比较的工具。

程序性能也受到一些全局策略的影响

  • 在解析XML文本的时候,相对DOM方法而言,SAX更快,而且内存效率更高。
  • 更多地使用C版本的模块也会提高程序性能,比如用cPickle来替代pickle模块,用cStringIO来替代StringIO。当然也要意识到一般而言C版本的模块可能会缺乏灵活性。
  • 在一些I/O读取较多的场合使用线程可以加快响应时间。
  • select模块可以帮助我们最小化从多个socket抓取数据的开销。

考虑使用额外的工具来提高性能

  • 对于大规模的数值计算而言,numpy更有效率。
  • psyco和pyrex能够加速本地代码。然而也要注意它们的一些限制,比如说并不支持所有的构造器。
  • See the SciPy-related document “A beginners guide to using Python for performance computing” for an interesting comparison of different tools, along with some timing results.

更多地性能提示

可以在PythonSpeed/PerformanceTips一文中找到更多的提升性能的技巧和例子。

试一下贴代码功能

恩,网上找的Python的singleton模式的修饰符方式实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
def singleton(cls):
    '''
    singleton 模式的修饰器,保留第一次初始化的值
    例:
    @singleton
    class Class:
        def __init__(self, v):
            self.val = v
    a = Class('a')
    b = Class('b')
    则b.val == 'a'
    a is b返回True
    '''
    instance_container = []
    def get_instance(*arg, **args):
        if not len(instance_container):
            instance_container.append(cls(*arg, **args))
        return instance_container[0]
    return get_instance

[仙剑]最终动画

也就是rng.mkf文件,解析出来了。这个貌似就是最终boss动画

[仙剑]YJ_1 Decoder完成

哇哈哈哈哈

很快就写完了,但debug了很久,被Python的self各种完虐,相当悲剧。后来在我的不懈努力加上Winpdb的帮助下终于把已知的都bug的消灭掉。现在能把动画解析出来了。上面似乎就是灵儿的某个雷系终极法术的效果。

不过话说回来winpdb还是很难用的,没有自定义变量、表达式的查看,而且数组一长的话还看不全。不得不说,真是大规模调试的话还是要上pydev+eclipse啊。

[仙剑]哈哈

仙剑搞笑图 FBP.mkf文件里面居然有一张这么有乐趣的图片

[仙剑]进展

这几天的进展还是不少的。

首先昨天晚上发现之前写的程序的一个bug,原来从mkf文件里面提出的文件总是少一段,后来才发现是漏了第一个索引的问题。这个故事说明别人写的摘要信一半就好了,具体还是要自己去分析体会。

然后现在的已经解析出了4个mkf文件的内容,包括midi(音乐)、rgm(对话头像)、gop(背景贴图)和ball(道具,为什么叫ball呢,也许是因为前面几张图片都是球状物体吧。。。)

这是rgm中的一张图片林月如

最后呢,由于其它的mkf文件大都经过YJ_1压缩(大宇当年居然创造出这么多特立独行的格式,实在是太无语了),所以现在还在写YJ_1解压缩程序

最近安装了一些Vim的插件,做个备忘

计有

TagList Ctags WinManager Pydiction python_ifold pyflakes Calendar 其中taglist和Ctags很好很强大,其它的一般般,pydiction作为一个自动补全工具,只能补全系统原有的函数,没什么用处。