Julia pi近似慢

pav*_*elf 4 julia

我的pi近似代码与官方页面上的代码非常相似:

function piaprox()
    sum = 1.0
    for i = 2:m-1
        sum = sum + (1.0/(i*i))
    end
end

m = parse(Int,ARGS[1])
opak = parse(Int,ARGS[2])

@time for i = 0:opak
    piaprox()
end
Run Code Online (Sandbox Code Playgroud)

当我尝试比较C和Julia的时间时,Julia明显变慢,m = 100000000几乎为38秒(C的时间为0.1608328933秒).为什么会这样?

Rez*_*lan 13

julia> m=100000000 
julia> function piaprox()
           sum = 1.0
           for i = 2:m-1
               sum = sum + (1.0/(i*i))
           end
       end
piaprox (generic function with 1 method)

julia> @time piaprox()
 28.482094 seconds (600.00 M allocations: 10.431 GB, 3.28% gc time)
Run Code Online (Sandbox Code Playgroud)

我想提一下julia文档的Performance Tips部分中的两个非常重要的段落:

避免全局变量全局变量可能具有其值,因此其类型随时都会发生变化.这使编译器难以使用全局变量优化代码.变量应该是本地的,或者尽可能作为参数传递给函数.....

@code_warntype(或其函数变量code_warntype())有时可以帮助诊断与类型相关的问题.

julia> @code_warntype piaprox();
Variables:
  sum::Any
  #s1::Any
  i::Any
Run Code Online (Sandbox Code Playgroud)

@code_warntype输出中可以清楚地看出,编译器无法识别局部变量的类型piaprox().所以我们尝试声明类型并删除全局变量:

function piaprox(m::Int)
    sum::Float64 = 1.0
    i::Int = 0
    for i = 2:m-1
        sum = sum + (1.0/(i*i))
    end
end
julia> @time piaprox(100000000 )
  0.009023 seconds (11.10 k allocations: 399.769 KB)
julia> @code_warntype piaprox(100000000);
Variables:
  m::Int64
  sum::Float64
  i::Int64
  #s1::Int64
Run Code Online (Sandbox Code Playgroud)

编辑

正如@ user3662120评论的那样,答案的超快行为是错误的结果,没有返回值LLVM可能会忽略for循环,通过添加返回行,@time结果将是:

julia> @time piaprox(100000000)
  0.746795 seconds (11.11 k allocations: 400.294 KB, 0.45% gc time)
1.644934057834575
Run Code Online (Sandbox Code Playgroud)

  • 请注意,"m"和"sum"上的类型注释不是速度所必需的. (4认同)
  • 类型注释(:: Int,:: Float64)实际上并没有对此处的性能做出任何贡献.(添加无用的类型注释是一个常见的Julia错误.)另请注意,您忘记返回总和.(LLVM可能实际上优化了整个循环!) (2认同)