julia:关于函数中泛型类型的几个问题

Imp*_*p54 4 performance types julia

我正在向某些函数添加类型,即为了速度和清晰度。我对此有几个问题。我在这里问他们所有人,因为我看过其他帖子这样做。问题以粗体显示,以便于识别。

\n

我想向一个函数添加类型,用于计算向量中负值的数量。我想让它与 Int 和 Float 兼容,就像非类型化函数一样。虽然方便,但 Chris Rackauckas 建议不要这样做,请参阅如何声明可以具有 int 和 float 的数组类型的第一条评论,

\n
\n

您想同时使用整数和浮点数吗?由于性能原因,不建议这样做。但如果您愿意,可以使用 Union{Int64,Float64} 作为类型。

\n
\n

如果由于某种原因需要多态函数,那么更好的方法似乎是通过Union. 然而,对于这种特殊情况,由于Number和是和Real的超类型,我认为它们会比非类型化版本稍快一些。Int64Float64

\n

然而,至少在我的简单测试中,情况似乎并非如此。我测试了一个没有参数类型的函数,另一个带有Any,以及两个带有类型Number和 的函数Real,两者都是Float64和的超类型Int64

\n
notypes\nmedian time:      1.006 ms (0.00% GC)\nmean time:        1.152 ms (12.60% GC)\n\nany\nmedian time:      1.054 ms (0.00% GC)\nmean time:        1.197 ms (12.05% GC)\n\nunion\nmedian time:      1.062 ms (0.00% GC)\nmean time:        1.210 ms (12.09% GC)\n\nnumber\nmedian time:      1.110 ms (0.00% GC)\nmean time:        1.315 ms (14.18% GC)\n\nreal\nmedian time:      1.015 ms (0.00% GC)\nmean time:        1.168 ms (12.70% GC)\n\nfloat\nmedian time:      728.131 \xce\xbcs (0.00% GC)\nmean time:        829.031 \xce\xbcs (11.53% GC)\n
Run Code Online (Sandbox Code Playgroud)\n

Any显然,无类型函数与类型为和 的函数之间没有显着的改进Number。该Real功能似乎有非常轻微的改进,并且该Float64功能是唯一具有明显改进的功能。

\n

一个函数是否只有类型Int并且Float通常比没有类型的函数更快? Union{Int64,Float64}是只有两种类型的超类型,Number与 和不同Real,跨越更多类型。这就是为什么我认为该Union函数会比其他函数(Float版本除外)更快。一般来说 s 和非类型化一样慢吗Union

\n

与保持非类型化相比,使用Number和 等超类型键入函数是否有任何性能改进?Float

\n

为每种可能的参数类型定义一个函数是最佳的朱利安实践吗?在这种情况下,Int64并且Float64.

\n

为了方便而不是为了性能,是否有更短的方法来定义 Int-Float 函数?也许,通过在一开始就定义一个新类型?我尝试这样做:

\n
abstract type IF64 <: Union{Int64,Float64} end\n
Run Code Online (Sandbox Code Playgroud)\n

但出现错误

\n
invalid subtyping in definition of IF64\n
Run Code Online (Sandbox Code Playgroud)\n

另外,函数定义中的含义是什么?N(例如where {T<:Union{Int64,Float64},N}下面countMPvec_arrUnion给出的 \ 的定义)。

\n

最后,为什么该Float函数比其他函数占用更少的内存?( 609.06 KiBv. 921.56 KiB)(这是基准测试的输出;代码如下)

\n
all other functions\n  memory estimate:  921.56 KiB\n  allocs estimate:  38979\nfloat\n  memory estimate:  609.06 KiB\n  allocs estimate:  28979\n
Run Code Online (Sandbox Code Playgroud)\n

测试的完整代码:

\n
#= -------------------\n   The different versions of the function\n   -------------------\n=#\nfunction countMPvec_notypes(vec)\n    nneg = 0\n    lvec = length(vec)\n    for i in 1:lvec\n        if (vec[i] < 0)\n            nneg += 1\n        end\n    end\n    npos = lvec - nneg\n    return (nneg,npos)\nend\n\nfunction countMPvec_any(vec :: Any)\n    nneg = 0\n    lvec = length(vec)\n    for i in 1:lvec\n        if (vec[i] < 0)\n            nneg += 1\n        end\n    end\n    npos = lvec - nneg\n    return (nneg,npos)\nend\n\n# Works with Int and Float !!!\nfunction countMPvec_arrUnion(vec :: Array{T,1}) where {T<:Union{Int64,Float64},N}\n    nneg = 0\n    lvec = length(vec)\n    for i in 1:lvec\n        if (vec[i] < 0)\n            nneg += 1\n        end\n    end\n    npos = lvec - nneg\n    return (nneg,npos)\nend\n\n# Works with Int and Float !!!\nfunction countMPvec_arrNumber(vec :: Array{T,1}) where {T<:Number,N}\n    nneg = 0\n    lvec = length(vec)\n    for i in 1:lvec\n        if (vec[i] < 0)\n            nneg += 1\n        end\n    end\n    npos = lvec - nneg\n    return (nneg,npos)\nend\n\n# Works with Int and Float !!!\nfunction countMPvec_arrReal(vec :: Array{T,1}) where {T<:Real,N}\n    nneg = 0\n    lvec = length(vec)\n    for i in 1:lvec\n        if (vec[i] < 0)\n            nneg += 1\n        end\n    end\n    npos = lvec - nneg\n    return (nneg,npos)\nend\n\nfunction countMPvec_arrFloat(vec :: Array{Float64,1})\n    nneg = 0\n    lvec = length(vec)\n    for i in 1:lvec\n        if (vec[i] < 0)\n            nneg += 1\n        end\n    end\n    npos = lvec - nneg\n    return (nneg,npos)\nend\n\n#= -------------------\n   Functions for benchmark\n   -------------------\n=#\nnums = [1.3; -2; 5]\nnitertest = 10000\n\nfunction test_notypes()\n    for i in 1:nitertest\n        countMPvec_notypes(nums)\n    end\nend\nfunction test_any()\n    for i in 1:nitertest\n        countMPvec_any(nums)\n    end\nend\nfunction test_arrUnion()\n    for i in 1:nitertest\n        countMPvec_arrUnion(nums)\n    end\nend\nfunction test_arrNumber()\n    for i in 1:nitertest\n        countMPvec_arrNumber(nums)\n    end\nend\nfunction test_arrReal()\n    for i in 1:nitertest\n        countMPvec_arrReal(nums)\n    end\nend\nfunction test_arrFloat()\n    for i in 1:nitertest\n        countMPvec_arrFloat(nums)\n    end\nend\n
Run Code Online (Sandbox Code Playgroud)\n

然后是基准单元。其中每一项都应该单独运行。此外,最后给出了每个单元格的完整输出:

\n
import BenchmarkTools\nprintln("notypes")\n@BenchmarkTools.benchmark test_notypes()\n\nprintln("any")\n@BenchmarkTools.benchmark test_any()\n\nprintln("union")\n@BenchmarkTools.benchmark test_arrUnion()\n\nprintln("number")\n@BenchmarkTools.benchmark test_arrNumber()\n\nprintln("real")\n@BenchmarkTools.benchmark test_arrReal()\n\nprintln("float")\n@BenchmarkTools.benchmark test_arrFloat()\n\n#= -------------------\n   Output of the benchmarks\n   -------------------\n=#\n\nnotypes\nBenchmarkTools.Trial: \n  memory estimate:  921.56 KiB\n  allocs estimate:  38979\n  --------------\n  minimum time:     855.070 \xce\xbcs (0.00% GC)\n  median time:      1.006 ms (0.00% GC)\n  mean time:        1.152 ms (12.60% GC)\n  maximum time:     31.515 ms (91.59% GC)\n  --------------\n  samples:          4314\n  evals/sample:     1\n\nany\nBenchmarkTools.Trial: \n  memory estimate:  921.56 KiB\n  allocs estimate:  38979\n  --------------\n  minimum time:     905.317 \xce\xbcs (0.00% GC)\n  median time:      1.054 ms (0.00% GC)\n  mean time:        1.197 ms (12.05% GC)\n  maximum time:     30.355 ms (96.33% GC)\n  --------------\n  samples:          4152\n  evals/sample:     1\n\nunion\nBenchmarkTools.Trial: \n  memory estimate:  921.56 KiB\n  allocs estimate:  38979\n  --------------\n  minimum time:     914.563 \xce\xbcs (0.00% GC)\n  median time:      1.062 ms (0.00% GC)\n  mean time:        1.210 ms (12.09% GC)\n  maximum time:     32.472 ms (90.09% GC)\n  --------------\n  samples:          4111\n  evals/sample:     1\n\nnumber\nBenchmarkTools.Trial: \n  memory estimate:  921.56 KiB\n  allocs estimate:  38979\n  --------------\n  minimum time:     926.189 \xce\xbcs (0.00% GC)\n  median time:      1.110 ms (0.00% GC)\n  mean time:        1.315 ms (14.18% GC)\n  maximum time:     42.545 ms (97.21% GC)\n  --------------\n  samples:          3788\n  evals/sample:     1\n\nreal\nBenchmarkTools.Trial: \n  memory estimate:  921.56 KiB\n  allocs estimate:  38979\n  --------------\n  minimum time:     863.699 \xce\xbcs (0.00% GC)\n  median time:      1.015 ms (0.00% GC)\n  mean time:        1.168 ms (12.70% GC)\n  maximum time:     31.847 ms (96.50% GC)\n  --------------\n  samples:          4257\n  evals/sample:     1\n\nfloat\nBenchmarkTools.Trial: \n  memory estimate:  609.06 KiB\n  allocs estimate:  28979\n  --------------\n  minimum time:     625.845 \xce\xbcs (0.00% GC)\n  median time:      728.131 \xce\xbcs (0.00% GC)\n  mean time:        829.031 \xce\xbcs (11.53% GC)\n  maximum time:     30.811 ms (97.38% GC)\n  --------------\n  samples:          5989\n  evals/sample:     1\n
Run Code Online (Sandbox Code Playgroud)\n

tho*_*oly 11

所有与性能相关的问题都有一个答案:类型注释可以提高结构的性能,但通常不会提高函数的性能。您从 Chris 那里读到的文章涉及数组(结构)的元素类型,尽管它是以函数可接受的类型的形式出现的。您应该在这种情况下解释它。

在 Julia 中,您应该对函数参数进行类型注释以控制调度,而不是为了性能。为什么?因为编译器将为您传递给它的每个具体类型专门化每个函数,从某种意义上说,它会自动生成您想要手动编写的所有那些专门化。因此添加类型注释的唯一原因是控制调用哪个方法:

is_this_a_number(x::Number) = true
is_this_a_number(x) = false
Run Code Online (Sandbox Code Playgroud)

结构则是另一回事。您可以在手册的性能提示部分阅读有关结构中类型注释的更多信息。

最后,请记住,自该问题提出之初以来,有些事情已经发生了变化。特别是,在许多情况下,联合分割Union可以在具有较小具体类型的情况下提供良好的性能(isconcretetype如果您不确定,请检查每个 )。

函数定义中的 N 是什么意思

数组中的维数。