49

这篇文章之后,我决定将 Julia 与 GNU Octave 进行基准测试,结果与julialang.org中说明的加速不一致。

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

GNU 八度

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.

--

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.

朱莉娅

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

--

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

有人可以解释为什么 Julia 在这些基本操作上比 GNU Octave 慢吗?加热后,它应该调用 LAPACK/BLAS 没有开销,对吧?

编辑:

正如评论和答案中所解释的,上面的代码不是一个好的基准,也不是说明在实际应用程序中使用该语言的好处。我曾经认为 Julia 是一个更快的“Octave/MATLAB”,但它远不止于此。这是朝着高效、高性能、科学计算迈出的一大步。通过使用 Julia,我能够 1) 在我的研究领域中使用 Fortran 和 C++ 编写的软件表现出色,并且 2) 为用户提供更好的 API。

4

2 回答 2

67

向量化操作.^正是 Octave 擅长的,因为它们实际上完全是用专门的 C 代码实现的。在构建 Octave 时编译的代码中的某处,有一个 C 函数计算.^一个双精度数和一个双精度数数组——这就是你在这里真正计时的地方,而且它很快,因为它是用 C 语言编写的。Julia 的.^运算符,在另一方面,是用 Julia 写的:

julia> a = 0.9999;

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

该定义包括:

.^(x::Number, r::Ranges) = [ x^y for y=r ]

它使用一维数组推导来提升range 中的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

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

于 2013-10-06T19:01:29.600 回答
16

您正在使用全局变量,这是 Julia 中的一个性能问题。

问题是,每当您的代码调用另一个函数时,全局变量可能会更改类型。结果,编译器必须生成极其缓慢的代码,无法对所使用的全局变量的类型做出任何假设。

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

于 2013-10-06T13:52:23.623 回答