加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

比较Speed Python3和Julia

发布时间:2020-12-20 12:38:44 所属栏目:Python 来源:网络整理
导读:我开始编写一个程序进行非线性光束计算.我之所以选择 Python是因为它的Matlab就像代码一样,而且我正在进行速度测试(确保python是正确的语言来进行快速数值计算)并尝试熟悉python3. 我尝试了一种算法,计算从t = 1到n的1 / t ^ 2之和(来自书Julia High Perfrom
我开始编写一个程序进行非线性光束计算.我之所以选择 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()

解决方法

1) In my calculations Julia is not as fast as expected? Julia ist JIT compiled. It should be very fast. Why ist python faster?

你的功能不是类型稳定的.由于它的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的类型是未知的.

2) Why are loops in python so slow?

因为Python中的变量是动态的.每当它命中一个变量时,解释器就需要找出变量是什么,为它找到正确的编译函数,并处理返回的值(可能进行一些转换以隐藏可能发生的真实底层变化).它本质上是一种非类型稳定的Julia函数.

3) Why is the python sum method slower than the numpy.sum method

编写NumPy假设该数组是浮点数的数组. Python数组(列表)通常是任何东西. Julia表示法是Vector {Float64} vs Vector {Any}.在第一个中,您可以准确地知道类型是什么,消除类型检查,转换等.您可以知道内存中每种类型的大小是相同的,并且由于它们都是相同的,您可以将它们内联到向量,而不是让内存成为一堆指向真实对象的指针(并且指针间接禁用了许多优化).

4) Why ist the sum function of python geting a slightly different solution than the numpy.sum function?

浮点很奇怪,不是关联的. SciPy中可能存在优化,这会改变某些计算的顺序,可能是某种循环展开

故事的道德启示

通过优化代码变得快速.如果编译器有更多信息,代码可以更好地优化,因为它可以做出更好的假设并删除许多不必要的检查和间接.完全动态的Python可以给解释器/运行时几乎没有信息,迫使它通过最少优化的路径.你可以通过调用用C编写的特定参数类型函数来改善这一点,因为编译器可以优化C代码(这就是SciPy所做的).

Julia旨在允许您为编译器提供静态编译语言的完整信息,但是使用的是大多数动态语言.这是由于类型系统和多次调度.因此,在这些情况下,它能够匹配C / Fortran的编译代码,获得全速,而无需在运行时调用FFI.如果您编写的代码中编译器不能拥有任何信息,例如使输出类型随机,那么编译器就无法进行优化,代码本质上变得动态且速度与Python一样慢.这很好,因为在这些情况下C只会出现段错误…

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读