python PerformanceTips
原文:http://wiki.python.org/moin/PythonSpeed/PerformanceTips
给自己做的笔记。
1,方法论
Get it right.
Test it’s right.
Profile if slow.
Optimise.
Repeat from 2.
2,选择合适的数据结构
3,sort小技巧:按某一维排序
def sortby(somelist, n): nlist = [(x[n], x) for x in somelist] nlist.sort() return [val for (key, val) in nlist] def sortby_inplace(somelist, n): somelist[:] = [(x[n], x) for x in somelist] somelist.sort() somelist[:] = [val for (key, val) in somelist] return //py2.4+ n = 1 import operator nlist.sort(key=operator.itemgetter(n))
另外:sort()操作是稳定的。
From Python 2.3 sort is guaranteed to be stable.
(to be precise, it’s stable in CPython 2.3, and guaranteed to be stable in Python 2.4)
4,字符串拼接
多用join和位置参数替换
slist = [some_function(elt) for elt in somelist] s = "".join(slist) out = "<html>%s%s%s%s</html>" % (head, prologue, query, tail)
避免+拼接产生的多个临时对象。
5,循环
多使用内置循环函数(如map):
newlist = [] for word in oldlist: newlist.append(word.upper()) newlist = [s.upper() for s in oldlist] newlist = map(str.upper, oldlist)
map也许对应了一个较优化的字节码。
6,避免名字查找(个人不提倡)
upper = str.upper newlist = [] append = newlist.append for word in oldlist: append(upper(word))
其实就是避免多次指针查询,而直接访问对应的locals()字典。
这是以牺牲可读性为代价的,个人觉得为了这一点点性能提升,完全没必要。
7,字典默认值
wdict = {} get = wdict.get for word in words: wdict[word] = get(word, 0) + 1
8,用xrange替代range
避免内存短爆,xrange is a generator object。
generator object记忆了内部变量和控制流为下次调用使用,基础是yield操作符。
记住控制流挺不寻常,以后要了解一下其内部实现。
9,profile工具
直接使用标准库中的profiling modules即可。
业务代码其实打点日志就行了,用不上profile工具。
原文中还介绍了几个工具。
10,总结
一句话:严格遵守方法论,选对数据结构,记住join和xrange。
这基本就够用了~
py3源码[7]-内存管理与垃圾收集
这块暂时只记录了py2.5的实现方式,尚未对照py3是否有变动。
一,内存管理
1,总体层次:type级(freelist);object级(关键);底层(clib:malloc/free)。
2,object级详解:
a,申请小内存(<256byte)时,采用内存池方式分配。否则直接malloc。
b,内存池层次:arenas->arena->pool->block,见下图
c,每个arena空间为定长256kb(具有一个arena_object头,图中未画出),存储着若干个pool;单个pool一般为页大小(4K),内联pool-header描述,存储某个定长(8Nbyte,max 256byte)的block;1个block为最小内存分配单位。
d,usedpools链表,用大小作为索引,串着同一个block大小的各个pool,作为分配总入口来加速分配。
e,一个arena空间都空闲的时候,是可以被收回的(>=py2.5,老版本存在内存泄漏)。
二,垃圾收集(GC)
1,引用计数+mark-sweep垃圾收集。为啥混合使用引用计数呢?这里有当时的设计思路。
2,引用计数:实现简单;具有实时性;对程序性能冲击小;垃圾收集:只针对容器对象(class,list,dict等),只处理循环引用。
3,垃圾收集三色标记,分代(3)收集,采用链表阈值触发收集,其中含有_del_方法的对象会导致内存泄漏。
leave a comment