这种性能比较有点奇怪,因为通常人们测量计算实质内容所需的时间,而不是看在一定时间内可以执行多少次微不足道的迭代。我尝试运行您提供的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代码在我的系统上运行,除非进行大量调整(但我并没有费心去做)。但是这里有一个使用time()
的f()
版本,我将其想象地称为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万次。所以我猜Julia在循环方面更快?耶!其实,这个循环中的主要工作是调用
time()
,因此...... 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
}
编译器看到循环,发现每次结果都相同,就直接返回那个常量值,而不是真正执行循环。当然,这需要零时间。