固定大小的数组已经在大小上进行了专门化。这些数组不适合当行数,N
根据您的情况,可能会有所不同。您注意到的任何性能问题可能是由于过度专业化.
让我说得更具体一些。
Julia 编译器能够通过对参数类型的积极专业化来实现零成本抽象。因此,一般来说(也就是说,在所有情况下,除了少数特殊化成本太高或被明确禁用的情况),如果使用两个不同的类型签名调用函数,则将编译该函数的两个版本。
由于a的大小Mat
是其类型的一部分,这意味着将为每个可能的大小编译一个版本Mat
。所以你所寻求的专业已经完成了。
然而,专业化并不是免费的。有两个与之相关的成本:
- 第一次对特定签名调用函数时,将分配内存并且必须运行编译器。
- 当无法推断类型的参数传递给函数时,存在“类型不稳定”,需要动态调度。动态调度涉及运行时查找。
因此,如果你的矩阵的大小(2, N)
, where N
变化并且在编译时未知,性能成本动态调度将会产生。这种性能成本可以通过使用函数屏障技术来限制:对于每个类型不稳定的调用,我们只产生一次该成本,因此限制此类调用的数量可以提高性能。
但是,完全避免这种动态调度会进一步提高性能。可以构造一个数组类型,该数组类型仅对类型中的列数进行编码,并在运行时将行数作为字段。也就是说,您的性能问题可能是由于过度专业化造成的,您需要创建类型以减少专业化程度。
找到正确的平衡点对于尽可能提高应用程序的性能至关重要。事实上,专门研究数组的大小很少有用,例如,即使是 C 和 C++ 代码也倾向于将数组大小作为运行时参数传递,而不是专门研究特定的数组大小。这并没有那么贵。在更多情况下并非如此,FixedSizeArrays.jl
不会提高性能,反而会损害性能。在某些情况下它肯定会有所帮助,但你的情况可能不是其中之一。
在你的情况下,为了获得最大性能,我怀疑这样的类型是最快的:
immutable TwoColumnMatrix{T, BaseType} <: AbstractArray{T, 2}
height::Int
base::BaseType
end
function TwoColumnMatrix(A::Matrix)
size(A, 2) == 2 || throw(ArgumentError("must be two columns"))
TwoColumnMatrix{eltype(A), typeof(A)}(size(A, 1), A)
end
Base.@propagate_inbounds function getindex(M::TwoColumnMatrix, n::Int)
M.base[n]
end
size(M::TwoColumnMatrix) = (M.height, 2)
您可能需要定义其他方法以获得最大性能,并一如既往地进行基准测试。包装器的开销可能不值得编译器了解维度。