比较Speed Python3和Julia
我开始编写一个程序进行非线性光束计算.我之所以选择
Python是因为它的Matlab就像代码一样,而且我正在进行速度测试(确保python是正确的语言来进行快速数值计算)并尝试熟悉python3.
我尝试了一种算法,计算从t = 1到n的1 / t ^ 2之和(来自书Julia High Perfromance),以比较python3与julia的速度. 现在我有一些问题: 1)在我的计算中,朱莉娅没有预期的那么快? Julia ist JIT编译.它应该非常快.为什么python更快? 2)为什么python中的循环如此缓慢? 3)为什么python sum方法比numpy.sum方法慢 4)为什么python geting的sum函数与numpy.sum函数的解决方案略有不同? 我希望你能帮助我. 代码: # Benchmark Python vs Julia # (from Julia High Performance page 7 from Avik Sengupta) import scipy as sp import time # Sum of 1/t^2 from t = 1 to n by using loops: # -------------------------------------------- def pisum(w,n): u_sum = 0 for vi in range(w): u_sum = 0 for vj in range(1,n+1,1): u_sum += 1.0/(vj*vj) return u_sum # Sum of 1/t^2 from t = 1 to n by using scipy functions: # ------------------------------------------------------ def pisum1(w,n): for vi in range(w): vj = sp.arange(1,1) vj = sp.multiply(vj,vj) u_sum_sp = (sp.divide(sp.ones(n),vj)).sum() return u_sum_sp # Sum of 1/t^2 from t = 1 to n by using scipy functions & calculating # the sum via pure python: # ------------------------------------------------------------------- def pisum2(w,vj) u_sum_py = sum(sp.divide(sp.ones(n),vj)) return u_sum_py # Benchmarking the methods : # ========================== w = 500 n = 10000 # 1) Loops: # --------- ta = time.clock() u_sum_loops = pisum(w,n) eltime_loops = time.clock() - ta # 2) scipy: # --------- ta = time.clock() u_sum_sp = pisum1(w,n) eltime_sp= time.clock() - ta # 3) scipy & sum via python: # -------------------------- ta = time.clock() u_sum_py = pisum2(w,n) eltime_py= time.clock() - ta # Julia with loops: # ----------------- eltime_ju_loops = 0.150857295 u_sum_ju = 1.6448340718480652 row_format = '{:<35} {:<5} {:<5} {:<} {:<}' print("Overview calculation time:") print("-"*50) print(row_format.format("elapsed time using loops:","%.5f" % eltime_loops,"sec. (","%.2f"% (eltime_loops/eltime_ju_loops),"*time Julia)")) print(row_format.format("elapsed time using scipy:","%.5f" % eltime_sp,"%.2f"% (eltime_sp/eltime_ju_loops),"*time Julia)")) print(row_format.format("elapsed time using python:","%.5f" % eltime_py,"%.2f"% (eltime_py/eltime_ju_loops),"*time Julia)")) print(row_format.format("elapsed time using Julia and loops:","%.5f" % eltime_ju_loops,"sec.","","n")) line1 = "sum loops:",u_sum_loops line2 = "sum scipy:",u_sum_sp line3 = "sum scipy and sum via python:",u_sum_py line4 = "sum_julia:",u_sum_ju row_format = '{:<29} {:<18}' print("Overview Sum:") print("-"*50) print(row_format.format(*line1)) print(row_format.format(*line2)) print(row_format.format(*line3)) print(row_format.format(*line4)) # Julia Code: # =========== # function pisum(w,n) # u_sum = 0; # for vi = 1:w # u_sum = 0; # for vj = 1:n # u_sum += 1.0/(vj*vj); # end # end # u_sum # end # # tic() # u_sum = pisum(500,10000) # eltime = toc() 解决方法
你的功能不是类型稳定的.由于它的JIT编译器,Julia并不快:因为它的类型系统它很快.它的类型系统被设计为在类型稳定函数(输出类型是输入类型的函数的函数)上使用多个调度,以在代码的每个阶段完全推导出类型,从而允许其函数基本上静态编译.通过这样做,通过将类型稳定函数链接在一起构建的函数本身可以通过类型稳定,并且与您想要编写的C / Fortran代码相比编译为1x(因为这对于所有人来说都是足够的信息)相关的编译器优化).这将在at this blog post中更详细地解释. 所以类型稳定的代码是: function pisum(w,n) u_sum = 0.0; for vi = 1:w u_sum = 0.0; for vj = 1:n u_sum += 1.0/(vj*vj); end end u_sum end @time u_sum = pisum(500,10000) 对我而言,这个时间大约为0.02秒,比SciPy示例快2倍,比计算机上的其他实现快50倍-100倍. 请注意,您可以通过调用@code_warntype pisum(500,10000)来检查类型稳定性,这将是大写和红色突出显示返回类型不是类型稳定的行.这将向您显示您的版本将u_sum作为Int启动,然后转换为Float64.想想你是否编写了一个静态编译的函数(C / Fortran):你无法编译,因为u_sum的类型是未知的.
因为Python中的变量是动态的.每当它命中一个变量时,解释器就需要找出变量是什么,为它找到正确的编译函数,并处理返回的值(可能进行一些转换以隐藏可能发生的真实底层变化).它本质上是一种非类型稳定的Julia函数.
编写NumPy假设该数组是浮点数的数组. Python数组(列表)通常是任何东西. Julia表示法是Vector {Float64} vs Vector {Any}.在第一个中,您可以准确地知道类型是什么,消除类型检查,转换等.您可以知道内存中每种类型的大小是相同的,并且由于它们都是相同的,您可以将它们内联到向量,而不是让内存成为一堆指向真实对象的指针(并且指针间接禁用了许多优化).
浮点很奇怪,不是关联的. SciPy中可能存在优化,这会改变某些计算的顺序,可能是某种循环展开 故事的道德启示 通过优化代码变得快速.如果编译器有更多信息,代码可以更好地优化,因为它可以做出更好的假设并删除许多不必要的检查和间接.完全动态的Python可以给解释器/运行时几乎没有信息,迫使它通过最少优化的路径.你可以通过调用用C编写的特定参数类型函数来改善这一点,因为编译器可以优化C代码(这就是SciPy所做的). Julia旨在允许您为编译器提供静态编译语言的完整信息,但是使用的是大多数动态语言.这是由于类型系统和多次调度.因此,在这些情况下,它能够匹配C / Fortran的编译代码,获得全速,而无需在运行时调用FFI.如果您编写的代码中编译器不能拥有任何信息,例如使输出类型随机,那么编译器就无法进行优化,代码本质上变得动态且速度与Python一样慢.这很好,因为在这些情况下C只会出现段错误… (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |