# NumPy is faster than Julia 1.11 for maximum function

**URL:** <https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451>\
**Category:** General Usage\
**Tags:** performance\
**Created:** [July 3, 2025, 1:18pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451 "2025-07-03T13:18:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [July 3, 2025, 1:18pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/1 "2025-07-03T13:18:04Z")

</div>

```julia
import numpy as np

A = np.rand(2026,51,251)
# %timeit np.max(A)
# 4.49 ms ± 89.2 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

```

Julia code:

```julia
using BenchmarkTools
const A=rand(2026,51,251)
@btime maximum(A)
# 6.946 ms (0 allocations: 0 bytes)

```

I am using `ipython` on Linux.

So in this example, Python is 55% faster than Julia.

Any idea?

---

<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:** [July 3, 2025, 1:19pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/2 "2025-07-03T13:19:10Z")

</div>

I wonder if this is [Madvise HUGEPAGE for large arrays · Issue #56521 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/56521).

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 3, 2025, 1:20pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/3 "2025-07-03T13:20:36Z")

</div>

Could be a threads thing.

```julia-repl
julia> @btime maximum(A);
  9.027 ms (0 allocations: 0 bytes)

julia> using OhMyThreads

julia> @btime treduce(max, A);
  3.625 ms (70 allocations: 3.86 KiB)

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 3, 2025, 1:21pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/4 "2025-07-03T13:21:39Z")

</div>

What version of Julia are you running? This is slated to improve significantly — by upwards of 6x on some platforms — on Julia v1.13 with julia#58267. I should check if that’s backport-able to v1.12.

On my machine, v1.11 takes 16.732 ms, whereas the nightly is 3.437 ms.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [July 3, 2025, 1:26pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/5 "2025-07-03T13:26:32Z")

</div>

Version 1.11.5 (2025-04-14)

I tried with Julia nightly, and indeed, I achieve the same performance as with Numpy:

```julia
 4.569 ms (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 3, 2025, 1:37pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/6 "2025-07-03T13:37:55Z")

</div>

On v1.11 and v1.10, you may see a slight advantage if you spell `maximum(A)` as `reduce((x,y)->max(x,y), A)`. That’s effectively what the change above does, but it relies upon some other core compiler improvements to really take effect.

```Julia
julia> using BenchmarkTools

julia> const A=rand(2026,51,251);

julia> @btime maximum(A)
  16.587 ms (0 allocations: 0 bytes)
0.999999980621013

julia> @btime reduce((x,y)->max(x,y), A)
  14.862 ms (0 allocations: 0 bytes)
0.999999980621013

julia> VERSION
v"1.11.5"

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 3, 2025, 1:38pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/7 "2025-07-03T13:38:52Z")

</div>

You can get the performance benefit of the nightly changes by just writing a loop:

```julia-repl
julia> function mymaximum(A)
           if isempty(A)
               error()
           end
           acc = typemin(eltype(A))
           @simd for x ∈ A
               acc = max(acc, x)
           end
           acc
       end;

julia> @btime mymaximum(A)
  3.896 ms (0 allocations: 0 bytes)
0.9999999569932408

```

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 3, 2025, 1:42pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/8 "2025-07-03T13:42:20Z")

</div>

I don’t think it’s that unreasonable if **NumPy** happens to be faster than Julia at some things. It’s just benchmarking one compiled kernel against another. NumPy tends to have a lot of really good arch-specific SIMD vectorizations.

Here is the code executed for max: [numpy/numpy/\_core/src/umath/loops\_minmax.dispatch.c.src at 85708b3c0bd3d2fdbcb00cb08d0a7b323ce3af2d · numpy/numpy · GitHub](https://github.com/numpy/numpy/blob/85708b3c0bd3d2fdbcb00cb08d0a7b323ce3af2d/numpy/_core/src/umath/loops_minmax.dispatch.c.src#L317-L446)

The actual python max (this one: `max(iterable, *[, default=obj, key=func]) -> value`) is much slower.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [July 3, 2025, 1:44pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/9 "2025-07-03T13:44:10Z")

</div>

> [@MilesCranmer](#):
>
> I don’t think it’s that unreasonable if **NumPy** happens to be faster than Julia at some things.

Sure. But it’s also not unreasonable to ask why julia ended up slower, and if there’s a fix. Julia tends to attract speed demons, and part of what makes it so fun to use the language (for some people) is that it’s so easy and engaging to tinker with performance problems.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 3, 2025, 1:50pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/10 "2025-07-03T13:50:53Z")

</div>

Also fair!

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 3, 2025, 1:53pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/11 "2025-07-03T13:53:15Z")

</div>

It is interesting that `maximum` in Julia is so slow relative to `sum`:

```julia
julia> const A = rand(2026, 51, 251);

julia> @btime sum($A);
  4.212 ms (0 allocations: 0 bytes)

julia> @btime maximum($A);
  18.033 ms (0 allocations: 0 bytes)

```

whereas in python they are similar (which makes sense I think)

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

In [2]: A = np.random.rand(2026, 51, 251)

In [4]: %timeit np.sum(A)
9.47 ms ± 1.56 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [5]: %timeit np.max(A)
10.7 ms ± 5.18 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

```

This is on an M1 Pro - Python 3.13.0 vs Julia 1.11.5

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 3, 2025, 1:55pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/12 "2025-07-03T13:55:21Z")

</div>

Even `foldl` is slightly faster:

```julia
julia> @btime foldl($max, $A)
  17.376 ms (0 allocations: 0 bytes)
0.999999966901279

julia> @btime maximum($A)
  17.850 ms (0 allocations: 0 bytes)
0.999999966901279

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 3, 2025, 2:00pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/13 "2025-07-03T14:00:32Z")

</div>

Reductions of `max` and `min` dispatched (by the type of that exact function) to a specialized kernel that worked around LLVM enable SIMD. It’s because of the particulars of floating point behaviors we need weren’t immediately exposed by LLVM in a SIMD-compatible way. Sums, on the other hand, don’t (and didn’t) have the same difficulty. For example, on v1.6 the generic implementation is _catestrophically_ slower than this optimization.

```julia-repl
julia> VERSION
v"1.6.7"

julia> using BenchmarkTools

julia> const A=rand(2026,51,251);

julia> @btime maximum(A)
  22.307 ms (0 allocations: 0 bytes)
0.9999999629120224

julia> @btime reduce((x,y)->max(x,y), A)
  124.803 ms (0 allocations: 0 bytes)
0.9999999629120224

julia> @btime foldl(max, A)
  125.503 ms (0 allocations: 0 bytes)
0.9999999629120224

```

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 3, 2025, 2:02pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/14 "2025-07-03T14:02:46Z")

</div>

FYI the times get better with LoopVectorization.jl again:

```julia
julia> function mymaximum(A)
            if isempty(A)
                error()
            end
            acc = typemin(eltype(A))
            @turbo for i in eachindex(A)
                acc = max(acc, A[i])
            end
            acc
        end;

julia> @btime mymaximum($A)
  4.104 ms (0 allocations: 0 bytes)
0.999999966901279

```

Long live LoopVectorization \<3

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 3, 2025, 2:09pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/15 "2025-07-03T14:09:37Z")

</div>

How does that compare against nightly on your architecture?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 3, 2025, 2:36pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/16 "2025-07-03T14:36:03Z")

</div>

Nice! Seems it is about equal to LoopVectorization on 1.13.0-DEV.811.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [July 3, 2025, 2:37pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/17 "2025-07-03T14:37:38Z")

</div>

(A backport would be lovely 😍 )

---

<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:** [July 3, 2025, 2:42pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/18 "2025-07-03T14:42:11Z")

</div>

Already [marked to be backported to v1.12](https://github.com/JuliaLang/julia/pull/58267#issuecomment-3032287440) (but not previous versions, because it needs other compiler changes to be effective).

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [July 3, 2025, 2:55pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/19 "2025-07-03T14:55:07Z")

</div>

I actually have a whole write up on this, but basically Numpy is doing fastmath by default.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/7/172c7fa84d8f513a432bdd24b5ef664da6582a3c.jpeg)

so if you do `@fastmath maximum` it should be equivalent.

And in the end if we don’t care about IEEE rules, we can do much better

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/d/cd578e2d8a99ee691f4a8d5293404259f552df75.jpeg)

My real problem with the Julia slow-down is in `findmin` and `findmax`, which still is a problem to this day.

---

<div class="post-metadata">

**Author:** ![karei](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/karei/32/214809_2.png) [@karei](https://discourse.julialang.org/u/karei)\
**Post date:** [July 3, 2025, 3:03pm UTC](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451/20 "2025-07-03T15:03:52Z")

</div>

`np.max` calls C to compute it, and it’s to be expected that it’s faster than a pure Julia implementation.  
`np.max->numpy.core.fromnumeric.amax->_wrapreduction->ufunc.reduce->ufunc_object.c`

Wouldn’t it?

[Next page](https://discourse.julialang.org/t/numpy-is-faster-than-julia-1-11-for-maximum-function/130451.md?page=2)
