# Why substituting "for loop" with direct assignment of Matrix worsen the performance time?

**URL:** <https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601>\
**Category:** General Usage\
**Tags:** question\
**Created:** [September 22, 2021, 8:01pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601 "2021-09-22T20:01:31Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [September 22, 2021, 8:01pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/1 "2021-09-22T20:01:31Z")

</div>

Why the execution time of “testS()” is faster than “testP()”, although the later has reduced a “for loop” (which is supposed to consume time) by a direct assignment of the Matrix, as shown below:

```julia
using BenchmarkTools

function testS(S,r) 

  for i in size(S,1)

    if r==1

      for j in size(S,2)

        S[i,j] = S[i,j] +1;

      end

    elseif r==2

      for j in size(S,2)

        S[i,j] = S[i,j] +2;

      end

    end 

  end 

end

function testP(S,r) 

  for i in size(S,1)

    if r==1

      S[i,:] = [S[i,1]+1 S[i,2]+1 S[i,3]+1 S[i,4]+1];

    elseif r==2

      S[i,:] = [S[i,1]+2 S[i,2]+2 S[i,3]+2 S[i,4]+2];

    end 

  end 

end

dt = 0.0001; 

tmin = 0;  

tmax = 1;  

timeSim = tmin:dt:tmax;

S = [0 0 0 0; 0 0 0 0; 0 0 0 0]

r = 1;

@btime begin for t in tmin:dt:tmax testS(S,r) end end 
# It gives 595.700 μs

@btime begin for t in tmin:dt:tmax testP(S,r) end end
# It gives 949.500 μs

```

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [September 22, 2021, 8:05pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/2 "2021-09-22T20:05:24Z")

</div>

` [S[i,1]+1 S[i,2]+1 S[i,3]+1 S[i,4]+1];` allocates an array. If you instead wrote `S[i,:] .+= 1`, you would recover the performance.

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [September 22, 2021, 8:26pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/3 "2021-09-22T20:26:53Z")

</div>

> [@Oscar\_Smith](#):
>
> `[S[i,1]+1 S[i,2]+1 S[i,3]+1 S[i,4]+1];` allocates an array. If you instead wrote `S[i,:] .+= 1` , you would recover the performance.

The problem is that in my real code the assignment is not the same for the matrix elements i.e.,

```julia
....
S[i,:] = [S[i,1]+4 S[i,2]+3 S[i,3]+6 S[i,4]+2];
...

```

---

<div class="post-metadata">

**Author:** ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)\
**Post date:** [September 22, 2021, 8:48pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/4 "2021-09-22T20:48:31Z")

</div>

Performance aside, your code is actually doing nothing other than `S[end] += r`. Also the matrix version is doing a different thing. Note: you might be used to Python’s `for i in range(n)` which will loop from `0` to `n-1`, in Julia, you must state explicitly `for i in 0:n-1`. In your code, `for i in size(S,1)` means `i = 3` and `for J in size(S,2)` means `j = 4`, so what you do is actually `S[3,4] += r` and the matrix form is different.

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [September 22, 2021, 8:54pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/5 "2021-09-22T20:54:50Z")

</div>

> [@Seif\_Shebl](#):
>
> Performance aside, your code is actually doing nothing other than `S[end] += r` . Also the matrix version is doing a different thing. Note: you might be used to Python’s `for i in range(n)` which will loop from `0` to `n-1` , in Julia, you must state explicitly `for i in 0:n-1` . In your code, `for i in size(S,1)` means `i = 3` and `for J in size(S,2)` means `j = 4` , so what you do is actually `S[3,4] += r` and the matrix form is different.

Yes, but lets say the following:

```julia
using BenchmarkTools

function testS(S,r) 
  for i in 1:size(S,1)
    if r==1
      for j in 1:size(S,2)
        S[i,j] = S[i,j] +i;
      end
    elseif r==2
      for j in 1:size(S,2)
        S[i,j] = S[i,j] +j;
      end
    end 
  end 
end

function testP(S,r) 
  for i in 1:size(S,1)
    if r==1
      S[i,:] = [S[i,1]+1 S[i,2]+4 S[i,3]+5 S[i,4]+6];
    elseif r==2
      S[i,:] = [S[i,1]+4 S[i,2]+2 S[i,3]+5 S[i,4]+2];
    end 
  end 
end

dt = 0.0001; 
tmin = 0;  
tmax = 1;  
timeSim = tmin:dt:tmax;
S = [0 0 0 0; 0 0 0 0; 0 0 0 0]
r = 1;
@btime begin for t in tmin:dt:tmax testS(S,r) end end # It gives 660.100 μs
@btime begin for t in tmin:dt:tmax testP(S,r) end end # It gives 1.550 ms

```

@Seif_Shebl @Oscar_Smith please have a look here!

---

<div class="post-metadata">

**Author:** ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)\
**Post date:** [September 22, 2021, 9:03pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/6 "2021-09-22T21:03:59Z")

</div>

Again, what your loop does is this:

```julia
if r == 1
    S .+= 1:size(S,1)
elseif r == 2
    S .+= (1:size(S,2))' 
end

```

You should take care of the dot in `.+=` as @Oscar_Smith said.  
And the matrix form does:

```julia
if r == 1
    S .+= [4 3 6 2]
elseif r == 2
    S .+= [4 2 5 2] 
end

```

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [September 22, 2021, 9:52pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/7 "2021-09-22T21:52:09Z")

</div>

> [@Amro](#):
>
> ```julia
> using BenchmarkTools
> 
> function testS(S,r) 
> for i in 1:size(S,1)
> if r==1
> for j in 1:size(S,2)
> S[i,j] = S[i,j] +i;
> end
> elseif r==2
> for j in 1:size(S,2)
> S[i,j] = S[i,j] +j;
> end
> end 
> end 
> end
> 
> function testP(S,r) 
> for i in 1:size(S,1)
> if r==1
> S[i,:] = [S[i,1]+1 S[i,2]+4 S[i,3]+5 S[i,4]+6];
> elseif r==2
> S[i,:] = [S[i,1]+4 S[i,2]+2 S[i,3]+5 S[i,4]+2];
> end 
> end 
> end
> 
> dt = 0.0001; 
> tmin = 0;  
> tmax = 1;  
> timeSim = tmin:dt:tmax;
> S = [0 0 0 0; 0 0 0 0; 0 0 0 0]
> r = 1;
> @btime begin for t in tmin:dt:tmax testS(S,r) end end # It gives 660.100 μs
> @btime begin for t in tmin:dt:tmax testP(S,r) end end # It gives 1.550 ms
> 
> ```

In my real code, the situation is as below:

```julia
using BenchmarkTools

function testS(S,r) 
  for i in 1:size(S,1)
    if r==1
      for j in 1:size(S,2)
        S[i,j] = S[i,j] +i;
      end
    elseif r==2
      for j in 1:size(S,2)
        S[i,j] = S[i,j] +j;
      end
    end 
  end 
end

function testP(S,r) 
  for i in 1:size(S,1)
    if r==1
      S[i,:] = [S[i,1]+1 S[i,2]+4 S[i,3]+5 S[i,4]+6];
    elseif r==2
      S[i,:] = [S[i,1]+4 S[i,2]+2 S[i,3]+5 S[i,4]+2];
    end 
  end 
end

dt = 0.0001; 
tmin = 0;  
tmax = 1;  
timeSim = tmin:dt:tmax;
S = [0 0 0 0; 0 0 0 0; 0 0 0 0]
r = 1;
@btime begin for t in tmin:dt:tmax testS(S,r) end end # It gives 660.100 μs
@btime begin for t in tmin:dt:tmax testP(S,r) end end # It gives 1.550 ms

```

@Seif_Shebl @Oscar_Smith

---

<div class="post-metadata">

**Author:** ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)\
**Post date:** [September 22, 2021, 9:58pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/8 "2021-09-22T21:58:45Z")

</div>

As I said, you’re comparing two different things, here is the same code with the matrix form actually faster:

```julia
function testS(S,r) 
  s1 = [1, 4, 5, 6]
  s2 = [4, 2, 5, 2]
  for i in 1:size(S,1)
    if r==1
      for j in 1:size(S,2)
        S[i,j] = S[i,j] + s1[j];
      end
    elseif r==2
      for j in 1:size(S,2)
        S[i,j] = S[i,j] + s2[j];
      end
    end 
  end 
end

function testP(S,r) 
  if r==1
    S .+= [1 4 5 6]
  elseif r==2
    S .+= [4 2 5 2]
  end 
end

@btime begin for t in tmin:dt:tmax testS($S,$r) end end   
@btime begin for t in tmin:dt:tmax testP($S,$r) end end     
  1.320 ms (49495 allocations: 2.43 MiB)
  1.191 ms (39494 allocations: 1.52 MiB)

```

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [September 22, 2021, 11:16pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/9 "2021-09-22T23:16:07Z")

</div>

@Seif_Shebl@Oscar_Smith thank you for your reply. Below, is my real code, in which I believe I am comparing between two similar things, but again the “for loop” gives faster performance:

```julia
using BenchmarkTools
using Parameters, Base;

Base.@kwdef mutable struct SSs
  PP::Vector{Float64} = [0,0,0]
  LL::Vector{Float64} = [0,0,0]
end #mutable struct RLC

function testS(S,r) 
  for i in 1:size(S,1)
    if r==1
      for j in 1:3
        S[i].LL[j] = S[i].PP[j]*S[i].PP[j]+1;
      end
    elseif r==2
      for j in 1:3
        S[i].LL[j] = S[i].PP[j]*S[i].PP[j]+2;
      end
    end 
  end 
end

function testP(S,r) 
  for i in 1:size(S,1)
    if r==1
      S[i].LL = S[i].PP.*S[i].PP.+1;
    elseif r==2
      S[i].LL = S[i].PP.*S[i].PP.+2;
    end 
  end 
end

dt = 0.0001; 
tmin = 0;  
tmax = 1;  
timeSim = tmin:dt:tmax;
S = SSs[];
push!(S, SSs());
S[1].PP = [2,3,1];
push!(S, SSs());
S[2].PP = [4,5,6];
r = 1;
@btime begin for t in tmin:dt:tmax testS(S,r) end end  
    640.000 μs
@btime begin for t in tmin:dt:tmax testP(S,r) end end
     1.166 ms

```

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [September 23, 2021, 2:38am UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/10 "2021-09-23T02:38:52Z")

</div>

You’re defining a new matrix here (which allocates more memory) and assigning it to the mutable slot `LL`:

```julia
S[i].LL = S[i].PP.*S[i].PP.+1

```

You need to instead use dot-assignment:

```julia
S[i].LL .= S[i].PP.*S[i].PP.+1

```

An abbreviated way to insert all those dots is the `@.` broadcast macro:

```julia
@. S[i].LL = S[i].PP^2 + 1

```

For such small arrays, you’re likely to get an additional speedup by substituting static/mutable arrays from StaticArrays.jl.

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [September 23, 2021, 7:06pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/11 "2021-09-23T19:06:26Z")

</div>

> [@stillyslalom](#):
>
> You’re defining a new matrix here (which allocates more memory) and assigning it to the mutable slot `LL` :

@stillyslalom Thanks for your reply.  
Actually, I didtn get why in my way, I am defining a new matrix. In other words, what does the dot is doing here?

> [@stillyslalom](#):
>
> For such small arrays, you’re likely to get an additional speedup by substituting static/mutable arrays from StaticArrays.jl.

Can you give me an example here?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 23, 2021, 7:18pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/12 "2021-09-23T19:18:11Z")

</div>

> [@Amro](#):
>
> ```julia
> Base.@kwdef mutable struct SSs
> PP::Vector{Float64} = [0,0,0]
> LL::Vector{Float64} = [0,0,0]
> end
> 
> ```

Take a look at this example, to understand what is going on:

```julia
julia> Base.@kwdef mutable struct SSs
         PP::Vector{Float64} = [0,0,0]
         LL::Vector{Float64} = [0,0,0]
       end
SSs

julia> pp1 = [1.,1.,1.]; ll1 = [2.,2.,2.];

julia> s1 = SSs(pp1,ll1)
SSs([1.0, 1.0, 1.0], [2.0, 2.0, 2.0])

julia> s1.PP = [0.,0.,0.] # this replaces the array PP
3-element Vector{Float64}:
 0.0
 0.0
 0.0

julia> pp1 # the original pp1 was not modified
3-element Vector{Float64}:
 1.0
 1.0
 1.0

julia> s1.LL .= [0.,0.,0.]; # note the . : this mutates s1.LL

julia> ll1 # the original array was modified
3-element Vector{Float64}:
 0.0
 0.0
 0.0

```

That said, only by writting `s1.LL = [0.,0.,0.]` (for example), you create the array `[0.,0.,0.]` which is a mutable object, and allocates memory. For this specific case you could use `s1.LL .= (0,0,0)`, which creates a tuple on the right side, but being immutable, tuples do not allocate memory (the compiler can optimize them out, it knows that their values or length won’t change).

The StaticArrays version of that would be:

```julia
julia> using StaticArrays

julia> Base.@kwdef mutable struct S
         PP::SVector{3,Float64} = @SVector [0,0,0]
         LL::SVector{3,Float64} = @SVector [0,0,0]
       end
S

julia> s = S()
S([0.0, 0.0, 0.0], [0.0, 0.0, 0.0])

julia> s.PP = @SVector [1.,1.,1.]; # one way

julia> s.LL = SVector{3,Float64}(2,2,2); # another way

julia> s
S([1.0, 1.0, 1.0], [2.0, 2.0, 2.0])

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [September 23, 2021, 7:29pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/13 "2021-09-23T19:29:46Z")

</div>

> [@lmiq](#):
>
> For this specific case you could use `s1.LL .= (0,0,0)`

Or just `s1.LL .= 0`

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [September 23, 2021, 7:33pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/14 "2021-09-23T19:33:26Z")

</div>

To the OP: unless you are performing matrix algebra, you can normally assume that ordinary loops will give the best performance.

Also, remember that Julia Arrays are column major, so try to let your inner loop iterate over the _first_ index, not the _second_, as shown in your MWE.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 23, 2021, 7:34pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/15 "2021-09-23T19:34:43Z")

</div>

> [@DNF](#):
>
> Or just `s1.LL .= 0`

Of course 😛

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [September 23, 2021, 7:51pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/16 "2021-09-23T19:51:46Z")

</div>

> [@lmiq](#):
>
> ```julia
> julia> Base.@kwdef mutable struct S
> PP::SVector{3,Float64} = @SVector [0,0,0]
> LL::SVector{3,Float64} = @SVector [0,0,0]
> end
> 
> ```

@lmiq Thank you very much for your explanation.  
Is the below correct for (3x3 Matrix{Float64, 2} )in the StaticArrays version?

```julia
Base.@kwdef mutable struct AAs
       Lss::SArray{Float64, 2} =@SArray [0 0 0; 0 0 0; 0 0 0]
       end

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 23, 2021, 7:53pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/17 "2021-09-23T19:53:58Z")

</div>

> [@Amro](#):
>
> `@SArray`

`@SMatrix` I think

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [September 23, 2021, 7:59pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/18 "2021-09-23T19:59:21Z")

</div>

Since you’re mutating your matrix, you’ll want to use `MMatrix` instead of `SMatrix`, with this type signature:

```julia
MMatrix{3, 3, Float64, 9}

```

With a mutable matrix, you _don’t_ need the container struct to be mutable itself.

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [September 23, 2021, 8:22pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/20 "2021-09-23T20:22:08Z")

</div>

> [@DNF](#):
>
> Also, remember that Julia Arrays are column major, so try to let your inner loop iterate over the _first_ index, not the _second_ , as shown in your MWE.

@DNF thank you for your explanation.  
What does “Julia Arrays are column major,” mean. Can you give me an example for " inner loop iterate over the _first_ index, not the _second_"?

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [September 23, 2021, 8:42pm UTC](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601/21 "2021-09-23T20:42:04Z")

</div>

Arrays are stored in contiguous, linear blocks of memory:

```julia
julia> v = [1:6...]
6-element Vector{Int64}:
 1
 2
 3
 4
 5
 6

```

Column-major matrices are contiguous along the first dimension, while row-major matrices are contiguous along the second:

```julia
julia> reshape(v, 2, 3) # column-major
2×3 Matrix{Int64}:
 1 3 5
 2 4 6

julia> reshape(v, 2, 3)' # transposed to row-major
3×2 adjoint(::Matrix{Int64}) with eltype Int64:
 1 2
 3 4
 5 6

```

The CPU is faster when it can operate on contiguous blocks of memory, so it’s better for the inner loop (with the fastest-changing index) to correspond to those contiguous blocks. For column-major languages like Julia, that means `w[1,1], w[2,1], w[3,1]` rather than `w[1,1], w[1,2], w[1,3]`. For example,

```julia
julia> function alongcolumns(w)
           for j in axes(w, 2)
               for i in axes(w, 1)
                   w[i, j] += 1
               end
           end
       end
alongcolumns (generic function with 1 method)

julia> function alongrows(w)
           for i in axes(w, 2)
               for j in axes(w, 1)
                   w[i, j] += 1
               end
           end
       end
alongrows (generic function with 1 method)

julia> w = rand(100, 100);

julia> @btime alongcolumns($w)
  710.000 ns (0 allocations: 0 bytes)

julia> @btime alongrows($w)
  2.889 μs (0 allocations: 0 bytes)

```

That’s a 4x difference, just by switching the loop order!

[Next page](https://discourse.julialang.org/t/why-substituting-for-loop-with-direct-assignment-of-matrix-worsen-the-performance-time/68601.md?page=2)
