大连比较好的建站公司,360浏览器网页,wordpress默认主题怎么用,毕业设计网站建设英文文献今天分享的这篇文章#xff0c;文字不多#xff0c;代码为主。绝对干货#xff0c;童叟无欺#xff0c;主要分享了提升 Python 性能的 20 个技巧#xff0c;教你如何告别慢Python。原文作者 开元#xff0c;全栈程序员#xff0c;使用 Python, Java, PHP和C。1. 优化算法…今天分享的这篇文章文字不多代码为主。绝对干货童叟无欺主要分享了提升 Python 性能的 20 个技巧教你如何告别慢Python。原文作者 开元全栈程序员使用 Python, Java, PHP和C。1. 优化算法时间复杂度算法的时间复杂度对程序的执行效率影响最大在Python中可以通过选择合适的数据结构来优化时间复杂度如list和set查找某一个元素的时间复杂度分别是O(n)和O(1)。不同的场景有不同的优化方式总得来说一般有分治分支界限贪心动态规划等思想。2. 减少冗余数据如用上三角或下三角的方式去保存一个大的对称矩阵。在0元素占大多数的矩阵里使用稀疏矩阵表示。3. 合理使用copy与deepcopy对于dict和list等数据结构的对象直接赋值使用的是引用的方式。而有些情况下需要复制整个对象这时可以使用copy包里的copy和deepcopy这两个函数的不同之处在于后者是递归复制的。效率也不一样(以下程序在ipython中运行)import copya range(100000)%timeit -n 10 copy.copy(a) # 运行10次 copy.copy(a)%timeit -n 10 copy.deepcopy(a)10 loops, best of 3: 1.55 ms per loop10 loops, best of 3: 151 ms per looptimeit后面的-n表示运行的次数后两行对应的是两个timeit的输出下同。由此可见后者慢一个数量级。4. 使用dict或set查找元素Python dict和set都是使用hash表来实现(类似c11标准库中unordered_map)查找元素的时间复杂度是O(1)。a range(1000)s set(a)d dict((i,1) for i in a)%timeit -n 10000 100 in d%timeit -n 10000 100 in s10000 loops, best of 3: 43.5 ns per loop10000 loops, best of 3: 49.6 ns per loopdict的效率略高(占用的空间也多一些)。5. 合理使用生成器(generator)和yield%timeit -n 100 a (i for i in range(100000))%timeit -n 100 b [i for i in range(100000)]100 loops, best of 3: 1.54 ms per loop100 loops, best of 3: 4.56 ms per loop使用()得到的是一个generator对象所需要的内存空间与列表的大小无关所以效率会高一些。在具体应用上比如set(i for i in range(100000))会比set([i for i in range(100000)])快。但是对于需要循环遍历的情况%timeit -n 10 for x in (i for i in range(100000)): pass%timeit -n 10 for x in [i for i in range(100000)]: pass10 loops, best of 3: 6.51 ms per loop10 loops, best of 3: 5.54 ms per loop后者的效率反而更高但是如果循环里有break,用generator的好处是显而易见的。yield也是用于创建generatordef yield_func(ls):for i in ls:yield i1def not_yield_func(ls):return [i1 for i in ls]ls range(1000000)%timeit -n 10 for i in yield_func(ls):pass%timeit -n 10 for i in not_yield_func(ls):pass10 loops, best of 3: 63.8 ms per loop10 loops, best of 3: 62.9 ms per loop对于内存不是非常大的list可以直接返回一个list但是可读性yield更佳(人个喜好)。python2.x内置generator功能的有xrange函数、itertools包等。6. 优化循环循环之外能做的事不要放在循环内比如下面的优化可以快一倍a range(10000)size_a len(a)%timeit -n 1000 for i in a: k len(a)%timeit -n 1000 for i in a: k size_a1000 loops, best of 3: 569 µs per loop1000 loops, best of 3: 256 µs per loop7. 优化包含多个判断表达式的顺序对于and应该把满足条件少的放在前面对于or把满足条件多的放在前面。如a range(2000)%timeit -n 100 [i for i in a if 10 i 20 or 1000 i 2000]%timeit -n 100 [i for i in a if 1000 i 2000 or 100 i 20]%timeit -n 100 [i for i in a if i % 2 0 and i 1900]%timeit -n 100 [i for i in a if i 1900 and i % 2 0]100 loops, best of 3: 287 µs per loop100 loops, best of 3: 214 µs per loop100 loops, best of 3: 128 µs per loop100 loops, best of 3: 56.1 µs per loop8. 使用join合并迭代器中的字符串In [1]: %%timeit...: s ...: for i in a:...: s i...:10000 loops, best of 3: 59.8 µs per loopIn [2]: %%timeits .join(a)...:100000 loops, best of 3: 11.8 µs per loopjoin对于累加的方式有大约5倍的提升。9. 选择合适的格式化字符方式s1, s2 ax, bx%timeit -n 100000 abc%s%s % (s1, s2)%timeit -n 100000 abc{0}{1}.format(s1, s2)%timeit -n 100000 abc s1 s2100000 loops, best of 3: 183 ns per loop100000 loops, best of 3: 169 ns per loop100000 loops, best of 3: 103 ns per loop三种情况中%的方式是最慢的但是三者的差距并不大(都非常快)。(个人觉得%的可读性最好)10. 不借助中间变量交换两个变量的值In [3]: %%timeit -n 10000a,b1,2....: ca;ab;bc;....:10000 loops, best of 3: 172 ns per loopIn [4]: %%timeit -n 10000a,b1,2a,bb,a....:10000 loops, best of 3: 86 ns per loop使用a,bb,a而不是ca;ab;bc;来交换a,b的值可以快1倍以上。11. 使用if isa range(10000)%timeit -n 100 [i for i in a if i True]%timeit -n 100 [i for i in a if i is True]100 loops, best of 3: 531 µs per loop100 loops, best of 3: 362 µs per loop使用 if is True 比 if True 将近快一倍。12. 使用级联比较x y zx, y, z 1,2,3%timeit -n 1000000 if x y z:pass%timeit -n 1000000 if x y and y z:pass1000000 loops, best of 3: 101 ns per loop1000000 loops, best of 3: 121 ns per loopx y z效率略高而且可读性更好。13. while 1 比 while True 更快def while_1():n 100000while 1:n - 1if n 0: breakdef while_true():n 100000while True:n - 1if n 0: breakm, n 1000000, 1000000%timeit -n 100 while_1()%timeit -n 100 while_true()100 loops, best of 3: 3.69 ms per loop100 loops, best of 3: 5.61 ms per loopwhile 1 比 while true快很多原因是在python2.x中True是一个全局变量而非关键字。14. 使用**而不是pow%timeit -n 10000 c pow(2,20)%timeit -n 10000 c 2**2010000 loops, best of 3: 284 ns per loop10000 loops, best of 3: 16.9 ns per loop**就是快10倍以上15. 使用 cProfile, cStringIO 和 cPickle等用c实现相同功能(分别对应profile, StringIO, pickle)的包import cPickleimport picklea range(10000)%timeit -n 100 x cPickle.dumps(a)%timeit -n 100 x pickle.dumps(a)100 loops, best of 3: 1.58 ms per loop100 loops, best of 3: 17 ms per loop由c实现的包速度快10倍以上16. 使用最佳的反序列化方式下面比较了eval, cPickle, json方式三种对相应字符串反序列化的效率import jsonimport cPicklea range(10000)s1 str(a)s2 cPickle.dumps(a)s3 json.dumps(a)%timeit -n 100 x eval(s1)%timeit -n 100 x cPickle.loads(s2)%timeit -n 100 x json.loads(s3)100 loops, best of 3: 16.8 ms per loop100 loops, best of 3: 2.02 ms per loop100 loops, best of 3: 798 µs per loop可见json比cPickle快近3倍比eval快20多倍。17. 使用C扩展(Extension)目前主要有CPython(python最常见的实现的方式)原生API, ctypes,Cythoncffi三种方式它们的作用是使得Python程序可以调用由C编译成的动态链接库其特点分别是CPython原生API:通过引入Python.h头文件对应的C程序中可以直接使用Python的数据结构。实现过程相对繁琐但是有比较大的适用范围。ctypes:通常用于封装(wrap)C程序让纯Python程序调用动态链接库(Windows中的dll或Unix中的so文件)中的函数。如果想要在python中使用已经有C类库使用ctypes是很好的选择有一些基准测试下python2ctypes是性能最好的方式。Cython:Cython是CPython的超集用于简化编写C扩展的过程。Cython的优点是语法简洁可以很好地兼容numpy等包含大量C扩展的库。Cython的使得场景一般是针对项目中某个算法或过程的优化。在某些测试中可以有几百倍的性能提升。cffi:cffi的就是ctypes在pypy(详见下文)中的实现同进也兼容CPython。cffi提供了在python使用C类库的方式可以直接在python代码中编写C代码同时支持链接到已有的C类库。使用这些优化方式一般是针对已有项目性能瓶颈模块的优化可以在少量改动原有项目的情况下大幅度地提高整个程序的运行效率。18. 并行编程因为GIL的存在Python很难充分利用多核CPU的优势。但是可以通过内置的模块multiprocessing实现下面几种并行模式多进程对于CPU密集型的程序可以使用multiprocessing的Process,Pool等封装好的类通过多进程的方式实现并行计算。但是因为进程中的通信成本比较大对于进程之间需要大量数据交互的程序效率未必有大的提高。多线程对于IO密集型的程序multiprocessing.dummy模块使用multiprocessing的接口封装threading使得多线程编程也变得非常轻松(比如可以使用Pool的map接口简洁高效)。分布式multiprocessing中的Managers类提供了可以在不同进程之共享数据的方式可以在此基础上开发出分布式的程序。不同的业务场景可以选择其中的一种或几种的组合实现程序性能的优化。19. 终级大杀器PyPyPyPy是用RPython(CPython的子集)实现的Python根据官网的基准测试数据它比CPython实现的Python要快6倍以上。快的原因是使用了Just-in-Time(JIT)编译器即动态编译器与静态编译器(如gcc,javac等)不同它是利用程序运行的过程的数据进行优化。由于历史原因目前pypy中还保留着GIL不过正在进行的STM项目试图将PyPy变成没有GIL的Python。如果python程序中含有C扩展(非cffi的方式)JIT的优化效果会大打折扣甚至比CPython慢(比Numpy)。所以在PyPy中最好用纯Python或使用cffi扩展。随着STMNumpy等项目的完善相信PyPy将会替代CPython。20. 使用性能分析工具除了上面在ipython使用到的timeit模块还有cProfile。cProfile的使用方式也非常简单python -m cProfile filename.pyfilename.py 是要运行程序的文件名可以在标准输出中看到每一个函数被调用的次数和运行的时间从而找到程序的性能瓶颈然后可以有针对性地优化。以上就是本文的全部内容希望对大家的学习有所帮助也希望大家多多支持脚本之家。