I find that an immutable type is usually faster to instantiate than a mutable type with the same field. For example,
julia> type MutableWithTuple
t::NTuple{5,Int64}
end
julia> immutable ImmutableWithTuple
t::NTuple{5,Int64}
end
julia> using BenchmarkTools
julia> @benchmark MutableWithTuple((0,1,2,3,4))
BenchmarkTools.Trial:
memory estimate: 48.00 bytes
allocs estimate: 1
--------------
minimum time: 10.504 ns (0.00% GC)
median time: 22.430 ns (0.00% GC)
mean time: 30.561 ns (18.68% GC)
maximum time: 3.945 ÎĽs (97.80% GC)
--------------
samples: 10000
evals/sample: 999
time tolerance: 5.00%
memory tolerance: 1.00%
julia> @benchmark ImmutableWithTuple((0,1,2,3,4))
BenchmarkTools.Trial:
memory estimate: 0.00 bytes
allocs estimate: 0
--------------
minimum time: 2.653 ns (0.00% GC)
median time: 3.238 ns (0.00% GC)
mean time: 4.549 ns (0.00% GC)
maximum time: 1.333 ÎĽs (0.00% GC)
--------------
samples: 10000
evals/sample: 1000
time tolerance: 5.00%
memory tolerance: 1.00%
Here, the two types are the same except that one is mutable and the other is immutable. We can see that it is a lot faster to instantiate the immutable type. The main reason seems to be the difference in the number of allocations.
However, if we create similar types with string fields instead of tuples, we do not get such performance difference:
julia> type MutableWithString
s::String
end
julia> immutable ImmutableWithString
s::String
end
julia> @benchmark MutableWithString("01234")
BenchmarkTools.Trial:
memory estimate: 16.00 bytes
allocs estimate: 1
--------------
minimum time: 10.401 ns (0.00% GC)
median time: 11.835 ns (0.00% GC)
mean time: 15.367 ns (11.84% GC)
maximum time: 3.035 ÎĽs (97.66% GC)
--------------
samples: 10000
evals/sample: 999
time tolerance: 5.00%
memory tolerance: 1.00%
julia> @benchmark ImmutableWithString("01234")
BenchmarkTools.Trial:
memory estimate: 16.00 bytes
allocs estimate: 1
--------------
minimum time: 10.190 ns (0.00% GC)
median time: 11.933 ns (0.00% GC)
mean time: 15.787 ns (12.76% GC)
maximum time: 3.684 ÎĽs (98.17% GC)
--------------
samples: 10000
evals/sample: 999
time tolerance: 5.00%
memory tolerance: 1.00%
Here are my questions:
-
When does making a type immutable reduce the number of allocations during instantiation, and when doesn’t? According to the above examples, this seems to be related the kinds of the fields the type has, but I thought both
String
andTuple
are immutable, so doesn’t understand why there is a difference between the type with a tuple and type with a string. -
For the type with a string field, is there a way to make the number of allocations zero? I am creating some type, and as soon as I introduce a string field (to give its instance a name), instantiation of the type becomes a lot slower, which is very frustrating.