我最近发现两个宏之间的巨大差异:@benchmark和@time在内存分配信息和时间方面。例如:
@benchmark quadgk(x -> x, 0., 1.)
BenchmarkTools.Trial:
memory estimate: 560 bytes
allocs estimate: 17
--------------
minimum time: 575.890 ns (0.00% GC)
median time: 595.049 ns (0.00% GC)
mean time: 787.248 ns (22.15% GC)
maximum time: 41.578 μs (97.60% GC)
--------------
samples: 10000
evals/sample: 182
@time quadgk(x -> x, 0., 1.)
0.234635 seconds (175.02 k allocations: 9.000 MiB)
(0.5, 0.0)
为什么这两个示例之间有很大差异?
原因是预编译开销。要查看此定义:
julia> h() = quadgk(x -> x, 0., 1.)
h (generic function with 1 method)
julia> @time h()
1.151921 seconds (915.60 k allocations: 48.166 MiB, 1.64% gc time)
(0.5, 0.0)
julia> @time h()
0.000013 seconds (21 allocations: 720 bytes)
(0.5, 0.0)
相对于
julia> @time quadgk(x -> x, 0., 1.)
0.312454 seconds (217.94 k allocations: 11.158 MiB, 2.37% gc time)
(0.5, 0.0)
julia> @time quadgk(x -> x, 0., 1.)
0.279686 seconds (180.17 k allocations: 9.234 MiB)
(0.5, 0.0)
这里发生的是,在第一次调用中,包装quadgk
在一个函数中,匿名函数x->x
只定义了一次,因为它被包装在一个函数中,因此quadgk
只被编译了一次。在第二个调用x->x
中,每次调用都要重新定义,因此每次都必须执行编译。
现在最关键的是BenchmarkTools.jl将代码包装在一个函数中,您可以通过检查generate_benchmark_definition
此程序包中函数的工作方式来检查它,因此它等效于上面介绍的第一种方法。
在不重新定义优化功能的情况下运行代码的另一种方法是:
julia> g(x) = x
g (generic function with 1 method)
julia> @time quadgk(g, 0., 1.)
1.184723 seconds (951.18 k allocations: 49.977 MiB, 1.58% gc time)
(0.5, 0.0)
julia> @time quadgk(g, 0., 1.)
0.000020 seconds (23 allocations: 752 bytes)
(0.5, 0.0)
(尽管这不是BenchmarkTools.jl的工作-我添加它是为了显示当您使用函数时,g
您不必两次支付预编译税)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句