Python与Julia的速度比较


9

我试图比较这两个片段,看看在一秒钟内可以完成多少次迭代。事实证明,Julia实现了250万次迭代,而Python实现了400万次迭代。朱莉娅不是应该更快吗?或者这两个片段不相等?

蟒蛇:

t1 = time.time()
i = 0
while True:
    i += 1
    if time.time() - t1 >= 1:
        break

朱莉娅:

function f()
    i = 0
    t1 = now()
    while true
        i += 1
        if now() - t1 >= Base.Dates.Millisecond(1000)
            break
        end
    end
    return i
end

4
我不确定Julia的工作方式,但似乎您必须为每次比较构造一个新对象,而Python正在进行简单的整数比较。
chepner

1
还请注意,这是某种穷人的速度比较,不是吗?如今,您可以使Python和Julia在适当的动机下(两端)以大致相同的速度运行。如果您这样做是要选择两种语言,请考虑使用哪种语言更容易思考。您可以在以后实际需要时对其进行优化。
norok2

@ norok2对于某些代码是正确的,但对于其他代码则不是。如果您能够将Python代码转换成对用快速语言编写的库函数的调用,或者numba支持或类似的功能,那么也许可以,但否则Python的运行速度会大大降低。
DNF

@DNF在某些方面,Python更快,而在其他方面,Julia更快。我相信您可以找到两者的示例。仅仅因为相对昂贵的显式循环和函数调用,Python才“显着地”(无论意味着什么)变慢了,而完全忽略了整个情况。当然,如果那是您的主力军,那么与朱莉娅在一起可能会更好。但是,如果使用正确的工具,则可以在Python中获得同等的速度。是值得学习这些工具还是更好地学习另一种语言。这很难说。
norok2

1
我使用两种语言,虽然有一些“两种”示例都可以使速度更快,但两者的平衡相当明显。这仅仅是Python被解释并且几乎完全不关注性能的结果,而Julia非常注重性能。实际上,这很像在说Python与C一样快。如果没有显着差异,那将是非常奇怪的事情,并且这会破坏Julia的许多目的。
DNF

Answers:


9

这是一种奇怪的性能比较,因为通常情况下,它会衡量计算某种物质所需的时间,而不是查看在一定时间内可以进行多少次微不足道的迭代。我无法让您的Python和Julia代码正常工作,所以我修改了Julia代码使其正常工作,只是没有运行Python代码。正如@chepner在评论中指出的那样,使用对象now()进行时间比较并进行比较DateTime非常昂贵。Python time.time()函数仅返回浮点值。事实证明,有一个名为Julia的函数time()可以执行完全相同的操作:

julia> time()
1.587648091474481e9

这是f()我的系统上原始功能(经过修改可正常工作)的时间:

julia> using Dates

julia> function f()
           i = 0
           t1 = now()
           while true
               i += 1
               if now() - t1 >= Millisecond(1000)
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
4943739

在时间用完之前,它进行了将近500万次迭代。就像我说的那样,我无法让您的Python代码在没有明显摆弄的情况下在我的系统上运行(我没有打扰过)。但是这f()是使用的一个版本time(),我将其想象性地称为g()

julia> function g()
           i = 0
           t1 = time()
           while true
               i += 1
               if time() - t1 >= 1
                   break
               end
           end
           return i
       end
g (generic function with 1 method)

julia> g()
36087637

该版本进行了3600万次迭代。所以我想朱莉娅在循环时更快?好极了!好吧,实际上,此循环中的主要工作是对time()so 的调用。Julia生成大量time()调用的速度更快!

为什么时间如此奇怪?正如我所说,这里的大多数实际工作都在打电话time()。循环的其余部分实际上没有执行任何操作。在优化的编译语言中,如果编译器看到一个循环不执行任何操作,它将完全消除循环。例如:

julia> function h()
           t = 0
           for i = 1:100_000_000
               t += i
           end
           return t
       end
h (generic function with 1 method)

julia> h()
5000000050000000

julia> @time h()
  0.000000 seconds
5000000050000000    

哇,零秒!那怎么可能?好吧,让我们看一下LLVM代码(有点像机器代码,但对于用作中间表示的假想机器),它降低为:

julia> @code_llvm h()

;  @ REPL[16]:1 within `h'
define i64 @julia_h_293() {
top:
;  @ REPL[16]:6 within `h'
  ret i64 5000000050000000
}

编译器看到了循环,发现每次的结果都是相同的,只返回该常数值而不实际执行循环。当然,这需要零时间。


这是编程语言的BogoMips
norok2

1
是的,但是bogomips用于测量CPU,而不是编程语言。但是可以肯定,这是一个可以衡量的事情。
StefanKarpinski,

4

您可能想time_ns在Julia中使用函数:

function f()
    i = 0
    t1 = time_ns()
    while true
        i += 1
        if time_ns() - t1 >= 10^9
            break
        end
    end
    return i
end

在我的计算机上,它的运行速度比Python快10倍。


4

好吧,这不是我在系统上观察到的:

的Python 3.7.7

Python 3.7.7 (default, Mar 26 2020, 15:48:22) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import time                                                                                                                                                       

In [2]: def f(): 
   ...:     t1 = time.time() 
   ...:     i = 0 
   ...:     while True: 
   ...:         i += 1 
   ...:         if time.time() - t1 >= 1: 
   ...:             return i 
   ...:                                                                                                                                                                   

In [3]: f()                                                                                                                                                               
Out[3]: 4676268


朱莉娅1.4.0:

julia> using Dates

julia> function f()
           i = 0
           t1 = now()
           while true
               i += 1
               if now() - t1 >= Dates.Millisecond(1000)
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
6339528

但是请注意,简单地使用time(即比较纯数字)仍然更快:

julia> function f()
           i = 0
           t1 = time()
           while true
               i += 1
               if time() - t1 >= 1
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
24742703


你不应该time.perf_counter_ns()在Python中使用吗?
norok2

使用time.perf_counter_ns不会更改此基准(至少在我的系统上)。我猜想,当以1秒为单位测量时间差时,时间测量的精度并不重要。在这里,只有进行测量和比较结果对象所花费的时间(以及循环本身的效率)才是重要的。
弗朗索瓦Févotte

在Julia中,测量时间很重要-这就是为什么在我的代码中我time_ns不使用time它的原因,因为它的速度要快30%。
博古米尔卡明斯基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.