gpt4 book ai didi

julia - 对传递函数的评估比 julia 中的直接评估慢。有解决方法吗?

转载 作者:行者123 更新时间:2023-12-03 22:00:31 25 4
gpt4 key购买 nike

假设我有很多不同的非常简单的函数,称为 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)

编辑 1:

在下面的最小示例中,我还可以问为什么函数 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)

编辑2:

谢谢您的回答。
我用解决方案更新了帖子。
using BenchmarkTools
f() = return 1
function g(x)
h = f
h()
end
const g2 = f
@btime f()
@btime g(f)
@btime g2()

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()

fFunctionAmbigiousType、fFunctionDeclaredType 和 fTuple 为您提供相同的速度。
向结构体声明函数的类型不会改变任何东西。 Julia 在这两种情况下都理解 typeof{f}。
参数结构或参数 NamedTuple 是可能的,但当然更慢,如果您经常应用该函数。如果您经常应用函数 f ,您应该首先将它传递给 g 或类似的东西,以避免每次都进行索引。

亲切的问候,
直到

最佳答案

你的问题有几个问题。

如何进行基准测试

实际上,在您的代码中,这两个函数都同样快。问题是g不是 const在全局范围内引入惩罚。看到这个声明 g作为常量或使用 $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


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

如何分析你的代码

但是,这种等价是人为的,因为您提取了 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

你会看到使用 fFunction struct 效率不高,因为它的 f1f2字段具有抽象类型(具体是 Any)。

如何编写一个包含函数的高效结构

使用 Tuple , NamedTuple或 struct 带参数,因为它们都提供类型信息。元组将简单地定义为 (f,f) , NamedTuple将是 (f1=f, f2=f) .最复杂的情​​况是参数结构,我在这里向您展示( TupleNamedTuple 的代码会更简单):
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

你可以看到使用 fFunction定义为参数类型几乎没有开销(您支付的唯一成本是字段提取)。

如果有不清楚的地方,请告诉我,我可以详细说明。

关于julia - 对传递函数的评估比 julia 中的直接评估慢。有解决方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52537402/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com