# Python3+@njit faster than julia (rs)

**URL:** https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932
**Category:** General Usage
**Tags:** performance
**Created:** [May 12, 2025, 7:59pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932 "2025-05-12T19:59:34Z")
**Posts on this page:** 11
**Page:** 1

<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: [May 12, 2025, 7:59pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/1 "2025-05-12T19:59:34Z")

</div>

Consider the simple following test:

```julia-repl
julia> using Chairmarks

julia> function test(f, m)
           size = length(f)
           for i in 1:size
               for j in 1:size
                   dij = m[i,j]
                   f[i] = dij
                   f[j] = -dij 
               end
           end
           return f
       end
test (generic function with 1 method)

julia> f = zeros(1000); m = rand(1000,1000);

julia> @b test($f, $m)
797.525 μs

```

The same runs faster in python, using the `numba` `@njit`:

```python
In [9]: import numpy as np

In [10]: from numba import njit, prange

In [11]: @njit(parallel=False, fastmath=False)
    ...: def test(f, m):
    ...: size = len(f)
    ...: for i in prange(size):
    ...: for j in prange(size):
    ...: dij = m[i,j]
    ...: f[i] = dij
    ...: f[j] = -dij
    ...: return f
    ...: 

In [13]: f = np.zeros(1000)

In [14]: m = np.random.random((1000,1000))

In [15]: %timeit test(f,m)
455 µs ± 2.97 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

```

I know how to rewrite the code in Julia to use `@turbo` and make that faster in this case, that is not the point. Is there a good reason for the Julia compiler not doing the same job as the `@njit` compiler here? Or is there other reason for the difference?

(`@inbounds` only does not make a difference there)

---

<div class="post-metadata">

### Author: ![Alexander-Barth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander-barth/32/3692_2.png) [@Alexander-Barth](https://discourse.julialang.org/u/Alexander-Barth)
#### Post date: [May 12, 2025, 8:09pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/2 "2025-05-12T20:09:34Z")

</div>

Reversing the loops gave me a significant performance spead-up in julia:

```julia
# your original function
julia> @btime test($f, $m);
  1.945 ms (0 allocations: 0 bytes)

julia> function test2(f, m)
                 size = length(f)
                 for j in 1:size
                     for i in 1:size
                         dij = m[i,j]
                         f[i] = dij
                         f[j] = -dij 
                     end
                 end
                 return f
             end
test2 (generic function with 1 method)

julia> @btime test2($f, $m);
  799.093 μs (0 allocations: 0 bytes)

```

---

<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: [May 12, 2025, 8:11pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/3 "2025-05-12T20:11:06Z")

</div>

Oh, yes, of course… dumb. Thanks.

---

<div class="post-metadata">

### Author: ![Alexander-Barth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander-barth/32/3692_2.png) [@Alexander-Barth](https://discourse.julialang.org/u/Alexander-Barth)
#### Post date: [May 12, 2025, 8:13pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/4 "2025-05-12T20:13:14Z")

</div>

I am wondering if julia is now on par with numba ?

---

<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: [May 12, 2025, 8:13pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/5 "2025-05-12T20:13:57Z")

</div>

Yes it is. But my actual code is different from that, and I may update the post if I don´t find the reason for the difference now.

---

<div class="post-metadata">

### Author: ![Alexander-Barth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander-barth/32/3692_2.png) [@Alexander-Barth](https://discourse.julialang.org/u/Alexander-Barth)
#### Post date: [May 12, 2025, 8:24pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/6 "2025-05-12T20:24:02Z")

</div>

Surprisingly even with “julia -O3”, the loops in `test(f,m)` are apparently not reordered.

---

<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: [May 12, 2025, 8:43pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/7 "2025-05-12T20:43:39Z")

</div>

Loop re-ordering is a very hard compiler optimization. LLVM currently does not do very much/well for loop optimizations like this.

---

<div class="post-metadata">

### Author: ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)
#### Post date: [May 12, 2025, 8:51pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/8 "2025-05-12T20:51:14Z")

</div>

Isn’t this the performance tip [Access arrays in memory order, along columns](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-column-major)? You’re looping over `m[i,j]` in the row-major order, which is better for languages like C and Python, while column-major is what Fortran and Julia use. Having the same exact code for Julia/Fortran and C/Python is pretty much guaranteed to favour one set of languages over the other when there’s this pattern.

---

<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: [May 12, 2025, 10:00pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/9 "2025-05-12T22:00:22Z")

</div>

Yes, of course, I’m simplifying another code where I have the performance issue and ended with that MWE. But it does not capture the original problem, which I’ll have to dig further.

---

<div class="post-metadata">

### Author: ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)
#### Post date: [May 13, 2025, 3:44am UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/10 "2025-05-13T03:44:34Z")

</div>

> [@Oscar\_Smith](#):
>
> Loop re-ordering is a very hard compiler optimization. LLVM currently does not do very much/well for loop optimizations like this.

Isn’t this what LoopModels is supposed to do? That said, since Chris has moved to Modular I have a nagging suspicion that LoopModels probably won’t see much more development 😔.

---

<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: [May 13, 2025, 1:08pm UTC](https://discourse.julialang.org/t/python3-njit-faster-than-julia-rs/128932/11 "2025-05-13T13:08:59Z")

</div>

Oh no! Damn the Python universe, it just drowns out everything.
