周末在家花了半天时间写了一个简单的双向循环链表,为什么要这样做,一是想比较一下Python原生的list和双向链表的性能差距是怎样的;二是看libuv的QUEUE源码,感觉libuv实现双向循环链表的方式还是很优雅的,打算借用一下。
代码地址:
https://github.com/Whosemario/ThinkIdeaEx/tree/master/python_list_ex
安装
> python setup.py build_ext --inplace
本地会生成一个listex.so的动态链接库。
性能对比
1.append方法
双向循环链表测试代码:
import time
import listex
li = listex.listex()
start_ts = time.time()
for i in xrange(0, 10000000):
li.append(i)
end_ts = time.time()
print "total time:", end_ts - start_ts
输出结果如下:
total time: 2.71579694748
原生Python List测试代码:
import time
import listex
li = listex.listex()
start_ts = time.time()
for i in xrange(0, 10000000):
li.append(i)
end_ts = time.time()
print "total time:", end_ts - start_ts
输出结果如下:
total time: 1.8892519474
上面的结果可以看出来Python List的append的效率更高,这个是在意料之中的,Python List向后插入本来性能就不差,原因是Python List在容量不足时候会扩容,容量足够的时候append的内部实现就是数组赋值,性能肯定不差;而我的listex,在每次插入一个PyObject的时候,都要malloc一个队列节点(ListexNode), 这个性能就会差很多了。
2.pop方法
原生Python List从下标为0的地方pop出值:
import time
import listex
li = []
for i in xrange(0, 100000):
li.append(i)
start_ts = time.time()
for i in xrange(0, 100000):
li.pop(0)
end_ts = time.time()
print "total time:", end_ts - start_ts
输出结果如下:
total time: 2.07851791382
使用listex,获取第一个listex node,并从队列中剔除:
import time
import listex
li = listex.listex()
for i in xrange(0, 100000):
li.append(i)
start_ts = time.time()
for i in xrange(0, 100000):
li.get_head().remove()
end_ts = time.time()
print "total time:", end_ts - start_ts
输出几个如下:
total time: 0.0255160331726
这种情况双向链表的优势就很明显了,Python List每次都要从头部pop出一个值,因此每次都要进行数据的整体移动,性能就很耗了。
关于此工程
现在这个双向链表的代码还是不完整,后面将会持续更新。