在 Julia 中将一些常量参数传递给函数的最有效方法是什么?
What is the most efficient way to pass some constant arguments to a function in Julia?
假设我有以下功能
function foo(x::Float64, a::Float64)
if do_some_intense_stuff(a)
return bar(x)
else
return baz(x)
end
end
让我们假设在 运行 时间 a
将是一个常数。但是 x
不会。我必须多次 运行 foo()
,所以我希望它尽可能快地 运行,这意味着尽可能少地 运行 宁 do_some_intense_stuff
。因为 a
是一个常量,所以在 运行 时我们知道 if
语句应该采用哪个分支。
理想情况下,我会执行以下操作:
foowrapper(x) = foo(x,a)
Y = [foowrapper(x) for x in lots_of_x]
而且会比
快很多
Y = [foo(x,a) for x in lots_of_x]
但事实并非如此。我不怪编译器没有优化我的代码,因为我没有明确告诉它 foo()
只会用 a
的常量值调用。但是我有什么好的方法吗?
当然,我总是可以摆脱 foo
并只在全局范围内编写 if
语句,但这似乎不够优雅,因为程序的其余部分不关心输出共 do_some_intense_stuff()
更新:
为了对下面建议的解决方案进行基准测试,我实现了如下功能。我还修改了 foo()
的声明,使 a
成为一个整数,原因很明显:
function bar(x::Float64)
return 2 * x
#println("Ran bar for value ",x)
end
function baz(x::Float64)
return -2 * x
#println("Ran baz for value ",x)
end
@memoize function do_some_intense_stuff(a::Int64)
return isprime(a + 32614262352646106013967035018546810367130464316134634614)
end
并定义了lots_of_x = 1.0:1.0:1000.0
.
这里是 @benchmark Y = [foo(x,a) for x in lots_of_x ]
使用和不使用 memoize 的输出:
没有:
BenchmarkTools.Trial:
memory estimate: 109.50 KiB
allocs estimate: 5001
--------------
minimum time: 6.858 ms (0.00% GC)
median time: 6.924 ms (0.00% GC)
mean time: 7.067 ms (0.77% GC)
maximum time: 78.747 ms (49.00% GC)
--------------
samples: 707
evals/sample: 1
与:
BenchmarkTools.Trial:
memory estimate: 39.19 KiB
allocs estimate: 2001
--------------
minimum time: 97.500 μs (0.00% GC)
median time: 98.801 μs (0.00% GC)
mean time: 108.897 μs (1.37% GC)
maximum time: 2.099 ms (93.76% GC)
--------------
samples: 10000
也许缓存您对 do_some_intense_stuff(a)
的调用结果会有所帮助,例如使用 Memoize.jl.
假设我有以下功能
function foo(x::Float64, a::Float64)
if do_some_intense_stuff(a)
return bar(x)
else
return baz(x)
end
end
让我们假设在 运行 时间 a
将是一个常数。但是 x
不会。我必须多次 运行 foo()
,所以我希望它尽可能快地 运行,这意味着尽可能少地 运行 宁 do_some_intense_stuff
。因为 a
是一个常量,所以在 运行 时我们知道 if
语句应该采用哪个分支。
理想情况下,我会执行以下操作:
foowrapper(x) = foo(x,a)
Y = [foowrapper(x) for x in lots_of_x]
而且会比
快很多Y = [foo(x,a) for x in lots_of_x]
但事实并非如此。我不怪编译器没有优化我的代码,因为我没有明确告诉它 foo()
只会用 a
的常量值调用。但是我有什么好的方法吗?
当然,我总是可以摆脱 foo
并只在全局范围内编写 if
语句,但这似乎不够优雅,因为程序的其余部分不关心输出共 do_some_intense_stuff()
更新:
为了对下面建议的解决方案进行基准测试,我实现了如下功能。我还修改了 foo()
的声明,使 a
成为一个整数,原因很明显:
function bar(x::Float64)
return 2 * x
#println("Ran bar for value ",x)
end
function baz(x::Float64)
return -2 * x
#println("Ran baz for value ",x)
end
@memoize function do_some_intense_stuff(a::Int64)
return isprime(a + 32614262352646106013967035018546810367130464316134634614)
end
并定义了lots_of_x = 1.0:1.0:1000.0
.
这里是 @benchmark Y = [foo(x,a) for x in lots_of_x ]
使用和不使用 memoize 的输出:
没有:
BenchmarkTools.Trial:
memory estimate: 109.50 KiB
allocs estimate: 5001
--------------
minimum time: 6.858 ms (0.00% GC)
median time: 6.924 ms (0.00% GC)
mean time: 7.067 ms (0.77% GC)
maximum time: 78.747 ms (49.00% GC)
--------------
samples: 707
evals/sample: 1
与:
BenchmarkTools.Trial:
memory estimate: 39.19 KiB
allocs estimate: 2001
--------------
minimum time: 97.500 μs (0.00% GC)
median time: 98.801 μs (0.00% GC)
mean time: 108.897 μs (1.37% GC)
maximum time: 2.099 ms (93.76% GC)
--------------
samples: 10000
也许缓存您对 do_some_intense_stuff(a)
的调用结果会有所帮助,例如使用 Memoize.jl.