There are people who say Julia is idiot-proof.
As a veritable idiot, I had to put the statement to test.
- Take a very innocous array of integers. You might use one of them to store a simple table.
my_table = rand(1:100, 5, 5)
>>>
5×5 Array{Int64,2}:
76 41 23 5 74
87 61 36 9 95
6 61 90 14 74
52 44 1 94 21
24 83 53 19 41
- Now let me write a simple function that sets the
ith row to 1. Easy Peasy.
function set_row(table, row)
table[row, :] .= 1
end
- Let’s benchmark this function to see if I am leaking any memory.
@btime set_row(my_table, 1)
>>> 21.821 ns (1 allocation: 48 bytes)
- Wait. Why is it assigning 48 bytes to this function? That’s weird.
- By the way, what happens if you decide to set all rows to 1?
function set_all_rows(table)
for row=1:5 # all rows
table[row, :] .= 1
end
end
@btime set_all_rows(my_table)
>>> 19.852 ns (0 allocations: 0 bytes)
- Okay I think I understand what is going on here. If I don’t have a function parameter like
row, I don’t allocate memory. - Is that really what’s going on here? Let me try to write a function that only sets the second row to be 1.
function set_second_row(table)
table[2, :] .= 1 # only the second row
end
@btime set_second_row(my_table)
>>> 21.525 ns (1 allocation: 48 bytes)
- WTF? 48 bytes allocated. If I try to set the whole array to one, I don’t allocate any memory. But if I try to set one row to one, then I somehow need to make new space for this one row.
Swapping Rows
- Let’s try swapping rows.
function swap_rows(table, i, j)
table[i,:], table[j,:] = table[j,:], table[i,:]
end
my_table = rand(1:100, 5, 5)
# 5×5 Array{Int64,2}:
# 58 86 80 80 55
# 52 7 1 67 54
# 67 24 62 42 20
# 62 69 22 75 83
# 25 76 16 99 31
swap_rows(my_table, 2, 4) # SWAP row 2 and 4
my_table
# 5×5 Array{Int64,2}:
# 58 86 80 80 55
# 62 69 22 75 83
# 67 24 62 42 20
# 52 7 1 67 54
# 25 76 16 99 31
- Okay it looks like the rows have been swapped.
- What about memory allocation though?
@btime swap_rows(my_table, 2, 4)
118.901 ns (3 allocations: 288 bytes)
- Okay this is crazy.
- Maybe I need to write the code in the dumbest way possible, swapping elements one at a time.
function swap_rows_dumb(table, i, j)
for k=1:5
temp = table[i, k]
table[i,k] = table[j,k]
table[j,k] = temp
end
end
@btime swap_rows_dumb(my_table, 2, 4)
17.350 ns (0 allocations: 0 bytes)
- Okay, finally. Zero memory allocation.
- This makes me question why I am even trying to make it work with Julia.
- If I cannot do simple row operations without blowing up memory, why am I not coding directly in C?