How to efficiently iterate over a list of objects in julia?

Viewed 353

I want this code to run as fast as possible. And what is the most efficient way to iterate over a list of objects and change their fields or calculate some variables using them?
Here is my code:

mutable struct typeA
    a::Float64
end

mutable struct typeB
    b::Float64
end

mutable struct typeC
    c::Float64
end

types = Union{typeA, typeB, typeC}
function change(n::Int64, list::Array{types, 1})
    for i = 1:n
        j = rand(1:3)
        chosen = list[j]
        u = rand()
        if typeof(chosen) == typeA
            if u < chosen.a
                chosen.a = u
            end
        elseif typeof(chosen) == typeB
            if u < chosen.b
                chosen.b = u
            end
        elseif typeof(chosen) == typeC
            if u > chosen.c
                chosen.c = u
            end
        end
    end
    list
end       

list = Union{types}[typeA(0.7), typeB(0.5), typeC(0.9)]
@time change(10000, list)

And here is the results:

0.072776 seconds (85.81 k allocations: 4.694 MiB)

And for the second time:

0.001378 seconds (4 allocations: 160 bytes)

2 Answers

I understand that you want to speed up the inner loop part (without changing the general logic). If this is the case then change typeof(chosen) == typeA to typeof(chosen) === typeA or chosen isa typeA (the same for typeB and typeC) in the if and elseif clauses and you should see around 3x speedup.

I would go for multiple dispatch in this example:

change!(x::typeA, u) = if u < x.a; x.a = u; end
change!(x::typeB, u) = if u < x.b; x.b = u; end
change!(x::typeC, u) = if u > x.c; x.c = u; end

function change(n, list)
    for i = 1:n
        j = rand(1:3)
        chosen = list[j]
        u = rand()
        change!(chosen, u)
    end
    list
end

This gives a slight improvement over the previous answer. Further more I recommend using https://github.com/JuliaCI/BenchmarkTools.jl for benchmarking performance. With @btime change(10000, $list) I get

  • 615.299 μs (0 allocations: 0 bytes) for the original code
  • 198.800 μs (0 allocations: 0 bytes) after replacing == with === and
  • 193.601 μs (0 allocations: 0 bytes) with the multiple dispatch implementation.
Related