Sorry the code is a bit long but the middle testIt!
function is where the question is. If I run run()
as-is, there are ~160k allocations. However, if I comment out the code with i
, then there are no allocations. I’m assuming this is because it has to box i
to capture it in the closure. I ran @code_warntype on both cases and they’re both fine except there is an i::Core.Box
when the i
var is there. Is there way to structure this simply that will avoid allocations?
function itrCombis(f, v, ::Val{4})
len = length(v)
for i in 1:len
for j in i:len
for k in j:len
for l in k:len
f((v[i], v[j], v[k], v[l]))
end
end
end
end
end
function testIt!(res, v1, v2)
i = 0 # Ref{Int}(0)
function inner(c1, c2)
allCombi = Iterators.flatten(Iterators.product(c1, c2))
for combi in allCombi
i += 1 # i[] += 1
res[i] = combi[1] > 5.0 ? nothing : 2.0
end
return
end
function outer(c1)
itrCombis(c2 -> inner(c1, c2), v2, Val(4))
return
end
itrCombis(outer, v1, Val(4))
return
end
function run()
res = Vector{Union{Nothing,Float64}}(undef, 100000000)
num = 5
v1 = collect(1:num)
v2 = collect(1:num)
testIt!(res, v1, v2)
@time testIt!(res, v1, v2)
end
I tried using i = Ref{Int}(0)
and that helped a lot. But it still allocates (1 allocation: 16 bytes)
, which is much better. I could probably thread the index through the functions, but I wanted to ask if there is maybe some way to do this type of closures without allocations.
I was using the Combinatorics package originally, but discovered that its combinations function allocates, so that’s why I put in the itrCombis
function in the example here.