比较速度Python3和朱利

2024-10-01 09:16:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我开始写一个程序做非线性光束计算。我选择Python是因为它是类似Matlab的代码,而且我目前正在进行速度测试(以确定Python是否是进行快速数值计算的正确语言),并尝试熟悉python3。 我尝试了一种算法,从t=1到n计算1/t^2的和(摘自《朱丽叶高性能》一书),来比较Python3和茱莉亚的速度。 现在我有几个问题:

1)在我的计算中,朱莉娅没有预期的快?茱莉亚是JIT编译的。应该很快。为什么python更快?在

2)为什么python中的循环这么慢?在

3)为什么python sum方法比数字总和方法

4)为什么python的求和函数与数字总和功能?在

我希望你能帮助我。在

代码:

# 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,n+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,n):
    for vi in range(w):
        vj = sp.arange(1,n+1,1)
        vj = sp.multiply(vj,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,"sec. (", "%.2f"% (eltime_sp/eltime_ju_loops),"*time Julia)"))
print(row_format.format("elapsed time using python:","%.5f" % eltime_py,"sec. (","%.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()

Tags: pyformatfortimescipysprowusing
1条回答
网友
1楼 · 发布于 2024-10-01 09:16:36

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

您的函数类型不稳定。Julia的速度不是因为它的JIT编译器,而是因为它的类型系统。它的类型系统设计为对类型稳定的函数(输出类型是输入类型的函数)使用多个分派,以便在代码的每个阶段完全推断类型,从而允许基本上静态编译其函数。通过这样做,通过将类型稳定函数链接在一起而构建的函数本身可以按类型稳定进行编译,并且与您希望编写的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_sumInt开头,然后变成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}vsVector{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只会出现错误。。。在

相关问题 更多 >