After learning in Faster default Base.sort! for Julia about Sorting Networks I thought that we surely must have a package in Julia for that, and surely we do: SortingNetworks.jl
The problem is this:
using SortingNetworks, BenchmarkTools
n = 4
@benchmark for i in 1:10000 sort(rand(n)) end # 1.547 ms ± 211.471 μs
@benchmark for i in 1:10000 swapsort(rand(n)) end # 2.393 ms ± 356.063 μs
The whole point of using Sorting Networks is because they’re so much faster than Julia’s default sort
function for short vectors and yet, in the above implementation, Sorting Networks are hopelessly slow.
As it turns out SortintNetworks.jl
is dispatching by value where the value is the size of the vector. Although it makes sense that is precisely what makes it so slow. See the below implementation using a “dispatching by value” function instead.
function sortn!(x::Vector)
n = length(x)
n == 2 && return sort2!(x)
n == 3 && return sort3!(x)
n == 4 && return sort4!(x)
end
function sort4!(x)
swap(i,j) = x[j], x[i] = x[i], x[j]
x[2]>x[3] && swap(2,3)
x[1]>x[2] && swap(1,2); x[3]>x[4] && swap(3,4)
x[2]>x[3] && swap(2,3)
x[1]>x[2] && swap(1,2); x[3]>x[4] && swap(3,4)
true
end
And now the benchmarks show that, indeed, Sorting Networks are faster than Julia’s default sort!
:
n=4
@benchmark for i in 1:10000 sort!(rand(n)) end # 1.253 ms ± 172.871 μs
@benchmark for i in 1:10000 sortn!(rand(n)) end # 1.141 ms ± 201.472 μs
This raises some questions about dispatching by value, in particular; is dispatching by value inherently slow and not to be used when performance is critical?