@propagate_inbounds 在 Julia 中
@propagate_inbounds in Julia
考虑以下情况:
struct A <: AbstractArray{Int, 2}
N::Int
end
struct B <: AbstractArray{Int, 2}
A::A
Func
end
...
@inline Base.getindex(A::A, i::Int, j::Int) = begin
@boundscheck (1 <= i <= A.N && 1 <= j <= A.N) || throw(BoundsError())
i - j
end
Base.@propagate_inbounds Base.getindex(B::B, i::Int, j::Int) = begin
B.Func(B.A[i, j])
end
查看 docs and some 我确定在执行“@inbounds b[i, j]”(b 是类型 B 的数组)时会消除边界检查。然而,事实并非如此。我错过了什么?
仅使用您的定义这对我有用:
julia> f1(x, i, j) = return x[i,j]
f2(x, i, j) = @inbounds return x[i,j]
julia> f1(A(5), 123, 123)
ERROR: BoundsError
Stacktrace:
[1] getindex at ./REPL[3]:2 [inlined]
[2] f1(::A, ::Int64, ::Int64) at ./REPL[4]:1
julia> f2(A(5), 123, 123)
0
julia> f1(B(A(5), identity), 123, 123)
ERROR: BoundsError
Stacktrace:
[1] getindex at ./REPL[3]:2 [inlined]
[2] getindex at ./REPL[3]:6 [inlined]
[3] f1(::B, ::Int64, ::Int64) at ./REPL[4]:1
julia> f2(B(A(5), identity), 123, 123)
0
正如我在评论中提到的,@inbounds
仅在 type-stable 函数中有效。在全局范围(如 REPL)或类型不稳定的函数(如引用 non-constant 全局或 abstractly-typed 字段或数组的函数)中测试它不会删除这些边界检查。
请注意,您对 B
的定义可能会导致类型不稳定,因为 Julia 无法知道它存储的是什么函数。它们在您发布的最小示例中并不明显,但这可能是您更复杂的原始问题的根本原因。更好的定义是:
struct B{F} <: AbstractArray{Int, 2}
A::A
Func::F
end
考虑以下情况:
struct A <: AbstractArray{Int, 2}
N::Int
end
struct B <: AbstractArray{Int, 2}
A::A
Func
end
...
@inline Base.getindex(A::A, i::Int, j::Int) = begin
@boundscheck (1 <= i <= A.N && 1 <= j <= A.N) || throw(BoundsError())
i - j
end
Base.@propagate_inbounds Base.getindex(B::B, i::Int, j::Int) = begin
B.Func(B.A[i, j])
end
查看 docs and some
仅使用您的定义这对我有用:
julia> f1(x, i, j) = return x[i,j]
f2(x, i, j) = @inbounds return x[i,j]
julia> f1(A(5), 123, 123)
ERROR: BoundsError
Stacktrace:
[1] getindex at ./REPL[3]:2 [inlined]
[2] f1(::A, ::Int64, ::Int64) at ./REPL[4]:1
julia> f2(A(5), 123, 123)
0
julia> f1(B(A(5), identity), 123, 123)
ERROR: BoundsError
Stacktrace:
[1] getindex at ./REPL[3]:2 [inlined]
[2] getindex at ./REPL[3]:6 [inlined]
[3] f1(::B, ::Int64, ::Int64) at ./REPL[4]:1
julia> f2(B(A(5), identity), 123, 123)
0
正如我在评论中提到的,@inbounds
仅在 type-stable 函数中有效。在全局范围(如 REPL)或类型不稳定的函数(如引用 non-constant 全局或 abstractly-typed 字段或数组的函数)中测试它不会删除这些边界检查。
请注意,您对 B
的定义可能会导致类型不稳定,因为 Julia 无法知道它存储的是什么函数。它们在您发布的最小示例中并不明显,但这可能是您更复杂的原始问题的根本原因。更好的定义是:
struct B{F} <: AbstractArray{Int, 2}
A::A
Func::F
end