Julia语言真的和它声称的一样快吗?

jul*_*ohm 42 benchmarking octave julia

这篇文章之后,我决定将Julia与GNU Octave进行比较,结果与julialang.org中的加速结果不一致.

我编译了Julia和GNU Octave CXXFLAGS='-std=c++11 -O3',结果我得到了:

GNU Octave

a=0.9999;

tic;y=a.^(1:10000);toc
Elapsed time is 0.000159025 seconds.

tic;y=a.^(1:10000);toc
Elapsed time is 0.000162125 seconds.

tic;y=a.^(1:10000);toc
Elapsed time is 0.000159979 seconds.
Run Code Online (Sandbox Code Playgroud)

-

tic;y=cumprod(ones(1,10000)*a);toc
Elapsed time is 0.000280142 seconds.

tic;y=cumprod(ones(1,10000)*a);toc
Elapsed time is 0.000280142 seconds.

tic;y=cumprod(ones(1,10000)*a);toc
Elapsed time is 0.000277996 seconds.
Run Code Online (Sandbox Code Playgroud)

朱莉娅

tic();y=a.^(1:10000);toc()
elapsed time: 0.003486508 seconds

tic();y=a.^(1:10000);toc()
elapsed time: 0.003909662 seconds

tic();y=a.^(1:10000);toc()
elapsed time: 0.003465313 seconds
Run Code Online (Sandbox Code Playgroud)

-

tic();y=cumprod(ones(1,10000)*a);toc()
elapsed time: 0.001692931 seconds

tic();y=cumprod(ones(1,10000)*a);toc()
elapsed time: 0.001690245 seconds

tic();y=cumprod(ones(1,10000)*a);toc()
elapsed time: 0.001689241 seconds
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么Julia比这些基本操作慢于GNU Octave吗?温暖后,它应该在没有开销的情况下调用LAPACK/BLAS,对吧?

编辑:

正如评论和答案中所解释的那样,上面的代码不是一个好的基准,也没有说明在实际应用中使用该语言的好处.我曾经认为朱莉娅是一个更快的"Octave/MATLAB",但它远不止于此.这是迈向高效,高性能,科学计算的重要一步.通过使用Julia,我能够1)在我用Fortran和C++编写的研究领域中胜过软件,2)为用户提供更好的API.

Ste*_*ski 63

矢量化操作就像.^Octave擅长的那样,因为它们实际上完全是用专门的C代码实现的.在构建Octave时编译的代码中的某处,有一个C函数可以计算.^双精度数和一个双精度数组 - 这就是你真正在这里计时的时间,并且它很快,因为它是用C. Julia的.^运算符编写的,在另一方面,写在朱莉娅:

julia> a = 0.9999;

julia> @which a.^(1:10000)
.^(x::Number,r::Ranges{T}) at range.jl:327
Run Code Online (Sandbox Code Playgroud)

该定义包括:

.^(x::Number, r::Ranges) = [ x^y for y=r ]
Run Code Online (Sandbox Code Playgroud)

它使用一维数组理解来提升范围中的x每个值,将结果作为向量返回.yr

Edward Garson非常正确,不应该使用全局变量来获得Julia的最佳表现.原因是编译器无法很好地推断全局变量的类型,因为它们可以在执行离开当前范围的任何时候进行更改.离开当前范围听起来并不常见,但在Julia中,即使是索引到数组或添加两个整数等基本内容实际上也是方法调用,因此离开了当前范围.但是,在这个问题的代码中,所有的时间都花在了.^函数内部,所以a全局的事实并不重要:

julia> @elapsed a.^(1:10000)
0.000809698

julia> let a = 0.9999;
         @elapsed a.^(1:10000)
       end
0.000804208
Run Code Online (Sandbox Code Playgroud)

最后,如果你所做的只是在浮点阵列上调用矢量化操作,那么Octave就可以了.但是,即使在高级动态语言中,这通常也不会花费大部分时间.如果您发现自己想要使用for循环遍历数组,使用标量算法对每个元素进行操作,您会发现Octave在这种情况下非常慢 - 通常比C或Julia代码慢几千倍同一件事情.另一方面,在Julia中编写for循环是一件非常合理的事情 - 事实上,我们所有的排序代码都是用Julia编写的,并且在性能上与C相当.使用Julia还有许多其他原因与性能无关.作为一个Matlab克隆,Octave继承了许多Matlab的设计问题,并没有 作为通用编程语言,它非常好.例如,您不希望在Octave或Matlab中编写Web服务,但它确实如此朱莉娅很容易做到这一点.

  • 很高兴帮助回答您的问题.作为一项政策,我们总是试图在C中实施一些事情.这使我们保持诚实 - 我们必须让Julia足够快以允许我们这样做.在我们可以使编译器更好,然后一切都变得更快 - 系统代码和用户代码相似之前,最好用语言做所有事情并稍微慢一些. (36认同)
  • 看起来“相当简单”的链接现在会导致 404 错误:( (2认同)

Edw*_*son 14

你正在使用全局变量,这是朱莉娅的性能问题.

问题是只要你的代码调用了anther函数,全局变量就可以改变类型.因此,编译器必须生成极其缓慢的代码,这些代码无法对所使用的全局变量类型做出任何假设.

根据https://docs.julialang.org/en/stable/manual/performance-tips/对代码进行简单修改可以产生更令人满意的结果.

  • 我简要地解释了为什么在我对你的问题的回答中发生这种情况.基本上,问题是当代码调用anther函数时,全局变量可能会改变类型.因此,编译器必须生成极其缓慢的代码,这些代码无法对所使用的全局变量类型做出任何假设. (4认同)