编写一个将 AbstractVector 作为参数的函数
Writing a function that will take an AbstractVector as its parameter
来自 Performance Tips:
When working with parameterized types, including arrays, it is best to
avoid parameterizing with abstract types where possible.
假设您正在编写一个需要 Vector
的函数,并且每次使用该函数时,Vector
可以包含不同的类型。
function selection_sort!(unsorted_vect::AbstractVector)
# Code to sort.
end
names = String["Sarah","Kathy","Amber"]
unsorted_fibonacci = Int32[8, 1, 34, 21, 3, 5, 0, 13, 2, 1]
selection_sort!(names)
selection_sort!(unsorted_fibonacci)
第一次使用selection_sort!()
时,Vector
包含String
,第二次Int32
.
该函数知道它正在获取一个 AbstractVector
,但它不知道元素的类型。
- 性能会不会低效?会不会和写
selection_sort!(unsorted_vect::AbstractVector{Real})
一样?
同节还说:
If you cannot avoid containers with abstract value types, it is
sometimes better to parametrize with Any to avoid runtime type
checking. E.g. IdDict{Any, Any} performs better than IdDict{Type,
Vector}
- 这样写函数会不会更好?
function selection_sort!(unsorted_vect::AbstractVector{Any})
如果是这样,为什么 sorting algorithms 只使用 AbstractVector
?
function sort!(v::AbstractVector, # left out other parameters)
您需要的是:
function selection_sort!(unsorted_vect::AbstractVector{T}) where T
# Code to sort.
end
这样你就有了容器的抽象类型(因此任何容器都会被接受)。
然而,这些容器可以是 non-abstract - 因为它们的元素可以有一个具体类型 - T
。正如 Bogumil 所指出的那样 - 如果在正文代码中您不需要 T
类型,您可以改为 function selection_sort!(unsorted_vect::AbstractVector)
。
但是,这只是参数类型的限制。 Julia 会很高兴拥有 function selection_sort!(unsorted_vect)
并且代码会同样高效。
真正重要的是参数的类型。考虑以下 3 个变量:
a = Vector{Float64}(rand(10))
b = Vector{Union{Float64,Int}}(rand(10))
c = Vector{Any}(rand(10))
a
是类型容器,b
是small-union类型容器,c
是抽象容器。让我们看看性能发生了什么:
julia> @btime minimum($a);
18.530 ns (0 allocations: 0 bytes)
julia> @btime minimum($b);
28.600 ns (0 allocations: 0 bytes)
julia> @btime minimum($c);
241.071 ns (9 allocations: 144 bytes)
变量 c
需要对值进行拆箱(由于元素类型未知),因此性能下降了一个数量级。
总而言之,参数类型才是真正重要的。
来自 Performance Tips:
When working with parameterized types, including arrays, it is best to avoid parameterizing with abstract types where possible.
假设您正在编写一个需要 Vector
的函数,并且每次使用该函数时,Vector
可以包含不同的类型。
function selection_sort!(unsorted_vect::AbstractVector)
# Code to sort.
end
names = String["Sarah","Kathy","Amber"]
unsorted_fibonacci = Int32[8, 1, 34, 21, 3, 5, 0, 13, 2, 1]
selection_sort!(names)
selection_sort!(unsorted_fibonacci)
第一次使用selection_sort!()
时,Vector
包含String
,第二次Int32
.
该函数知道它正在获取一个 AbstractVector
,但它不知道元素的类型。
- 性能会不会低效?会不会和写
selection_sort!(unsorted_vect::AbstractVector{Real})
一样?
同节还说:
If you cannot avoid containers with abstract value types, it is sometimes better to parametrize with Any to avoid runtime type checking. E.g. IdDict{Any, Any} performs better than IdDict{Type, Vector}
- 这样写函数会不会更好?
function selection_sort!(unsorted_vect::AbstractVector{Any})
如果是这样,为什么 sorting algorithms 只使用 AbstractVector
?
function sort!(v::AbstractVector, # left out other parameters)
您需要的是:
function selection_sort!(unsorted_vect::AbstractVector{T}) where T
# Code to sort.
end
这样你就有了容器的抽象类型(因此任何容器都会被接受)。
然而,这些容器可以是 non-abstract - 因为它们的元素可以有一个具体类型 - T
。正如 Bogumil 所指出的那样 - 如果在正文代码中您不需要 T
类型,您可以改为 function selection_sort!(unsorted_vect::AbstractVector)
。
但是,这只是参数类型的限制。 Julia 会很高兴拥有 function selection_sort!(unsorted_vect)
并且代码会同样高效。
真正重要的是参数的类型。考虑以下 3 个变量:
a = Vector{Float64}(rand(10))
b = Vector{Union{Float64,Int}}(rand(10))
c = Vector{Any}(rand(10))
a
是类型容器,b
是small-union类型容器,c
是抽象容器。让我们看看性能发生了什么:
julia> @btime minimum($a);
18.530 ns (0 allocations: 0 bytes)
julia> @btime minimum($b);
28.600 ns (0 allocations: 0 bytes)
julia> @btime minimum($c);
241.071 ns (9 allocations: 144 bytes)
变量 c
需要对值进行拆箱(由于元素类型未知),因此性能下降了一个数量级。
总而言之,参数类型才是真正重要的。