假设我有许多不同的非常简单的函数,称为f1,f2,....我想将所有f函数存储在fStruct中,并将其中一个f函数传递给例如g,当我在我的代码中需要它时.但是当我将函数f传递给g时,函数g()的求值要慢得多.有解决方法吗?我丑陋的解决方案是使用一个整体函数,它通过if-else语句选择正确的f()函数.下面是慢速计算的最小示例.
using BenchmarkTools
struct fFunction
f1
f2
end
f() = return 1
fStruct = fFunction(f, f)
g = fStruct.f1
@btime f() --> 0.001 ns (0 allocations: 0 bytes)
@btime g() --> 9.591 ns (0 allocations: 0 bytes)
Run Code Online (Sandbox Code Playgroud)
EDIT1:
我还可以问一下,为什么函数g比较慢,或者如何在下面的最小例子中使它像f一样快
using BenchmarkTools
f() = return 1
func = "f"
g = eval(Meta.parse(func))
f == g -->true
@btime f() --> 0.001 ns (0 allocations: 0 bytes)
@btime g() --> 11.907 ns (0 allocations: 0 bytes)
Run Code Online (Sandbox Code Playgroud)
EDIT2:
谢谢您的回答.我用解决方案更新帖子.
using BenchmarkTools
f() = return 1
function g(x)
h = f
h()
end
const g2 = f
@btime f()
@btime g(f)
@btime g2()
Run Code Online (Sandbox Code Playgroud)
f,g和g2给你相同的速度.
struct fFunctionAmbigiousType{F}
f1::F
f2::F
end
struct fFunctionDeclaredType{F}
f1::F
f2::F
end
fStructAmbigiousType = fFunctionAmbigiousType(f, f)
fStructDeclaredType = fFunctionDeclaredType(f, f)
fTuple = (f1 = f, f2 = f)
@btime $fStructAmbigiousType.f1
@btime $fStructDeclaredType.f1
@btime $fTuple.f1
fStructAmbigiousTypeFunctionPassed = fStructAmbigiousType.f1
fStructDeclaredTypeFunctionPassed = fStructDeclaredType.f1
fTupleFunctionPassed = fTuple.f1
@btime $fStructAmbigiousTypeFunctionPassed()
@btime $fStructDeclaredTypeFunctionPassed()
@btime $fTupleFunctionPassed()
Run Code Online (Sandbox Code Playgroud)
fFunctionAmbigiousType,fFunctionDeclaredType和fTuple为您提供相同的速度.向结构声明函数的类型不会改变任何东西.朱莉娅在两种情况下都理解{f}的类型.如果经常应用函数,则可以使用参数结构或参数化的NamedTuple,但当然速度较慢.如果您经常应用f函数,则应首先将其传递给g或类似的东西,以避免每次都进行索引.
亲切的问候,直到
你的问题有几个问题.
实际上在你的代码中,两个函数同样快.问题是g
不在const
全球范围内引入惩罚.要看到这个声明g
为const或$g
在@btime
调用中使用,看看没有区别:
julia> using BenchmarkTools
julia> struct fFunction
f1
f2
end
julia> f() = return 1
f (generic function with 1 method)
julia> fStruct = fFunction(f, f)
fFunction(f, f)
julia> const g = fStruct.f1
f (generic function with 1 method)
julia> @btime f()
0.001 ns (0 allocations: 0 bytes)
1
julia> @btime g()
0.001 ns (0 allocations: 0 bytes)
1
Run Code Online (Sandbox Code Playgroud)
和
julia> using BenchmarkTools
julia> struct fFunction
f1
f2
end
julia> f() = return 1
f (generic function with 1 method)
julia> fStruct = fFunction(f, f)
fFunction(f, f)
julia> g = fStruct.f1
f (generic function with 1 method)
julia> @btime f()
0.001 ns (0 allocations: 0 bytes)
1
julia> @btime $g()
0.001 ns (0 allocations: 0 bytes)
1
Run Code Online (Sandbox Code Playgroud)
但是,这种等价是人为的,因为您g
从fStruct
全局范围中提取,因此在调用之前对其进行求值@btime
.更合适的测试是:
julia> using BenchmarkTools
julia> struct fFunction
f1
f2
end
julia> f() = return 1
f (generic function with 1 method)
julia> fStruct = fFunction(f, f)
fFunction(f, f)
julia> test1() = f()
test1 (generic function with 1 method)
julia> test2(fStruct) = fStruct.f1()
test2 (generic function with 1 method)
julia> @btime test1()
0.001 ns (0 allocations: 0 bytes)
1
julia> @btime test2($fStruct)
14.462 ns (0 allocations: 0 bytes)
1
julia> @code_warntype test1()
Body::Int64
1 1 ? return 1 ?
julia> @code_warntype test2(fStruct)
Body::Any
1 1 ? %1 = (Base.getfield)(fStruct, :f1)::Any ?? getproperty
? %2 = (%1)()::Any ?
??? return %2
Run Code Online (Sandbox Code Playgroud)
并且您看到使用fFunction
struct不高效,因为它f1
和f2
字段具有抽象类型(Any
具体).
使用带参数的a Tuple
,a NamedTuple
或struct,因为它们都提供类型信息.元组将被简单地定义为(f,f)
,a NamedTuple
将是(f1=f, f2=f)
.最复杂的情况是参数结构,我在这里向您展示(代码为Tuple
,NamedTuple
甚至更简单):
julia> using BenchmarkTools
julia> struct fFunction{F1,F2}
f1::F1
f2::F2
end
julia> f() = return 1
f (generic function with 1 method)
julia> fStruct = fFunction(f, f)
fFunction{typeof(f),typeof(f)}(f, f)
julia> test1() = f()
test1 (generic function with 1 method)
julia> test2(fStruct) = fStruct.f1()
test2 (generic function with 1 method)
julia> @btime test1()
0.001 ns (0 allocations: 0 bytes)
1
julia> @btime test2($fStruct)
1.866 ns (0 allocations: 0 bytes)
1
julia> @code_warntype test1()
Body::Int64
1 1 ? return 1 ?
julia> @code_warntype test2(fStruct)
Body::Int64
1 1 ? (Base.getfield)(fStruct, :f1) ?? getproperty
??? return 1
Run Code Online (Sandbox Code Playgroud)
您可以看到使用fFunction
定义为参数类型几乎没有开销(您支付的唯一成本是字段提取).
如果问题不明确请告诉我,我可以详细说明.