Skip to content

Commit 024d42a

Browse files
authored
Loop over Iterators.rest in _foldl_impl (#56492)
For reasons that I don't understand, this improves performance in `mapreduce` in the following example: ```julia julia> function g(A) for col in axes(A,2) mapreduce(iszero, &, view(A, UnitRange(axes(A,1)), col), init=true) || return false end return true end g (generic function with 2 methods) julia> A = zeros(2, 10000); julia> @Btime g($A); 28.021 μs (0 allocations: 0 bytes) # nightly v"1.12.0-DEV.1571" 12.462 μs (0 allocations: 0 bytes) # this PR julia> A = zeros(1000,1000); julia> @Btime g($A); 372.080 μs (0 allocations: 0 bytes) # nightly 321.753 μs (0 allocations: 0 bytes) # this PR ``` It would be good to understand what the underlying issue is, as the two seem equivalent to me. Perhaps this form makes it clear that it's not, in fact, an infinite loop?
1 parent 473d0db commit 024d42a

File tree

1 file changed

+6
-6
lines changed

1 file changed

+6
-6
lines changed

base/reduce.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ function foldl_impl(op::OP, nt, itr) where {OP}
4343
end
4444

4545
function _foldl_impl(op::OP, init, itr) where {OP}
46-
# Unroll the while loop once; if init is known, the call to op may
47-
# be evaluated at compile time
46+
# Unroll the loop once to check if the iterator is empty.
47+
# If init is known, the call to op may be evaluated at compile time
4848
y = iterate(itr)
4949
y === nothing && return init
5050
v = op(init, y[1])
51-
while true
52-
y = iterate(itr, y[2])
53-
y === nothing && break
54-
v = op(v, y[1])
51+
# Using a for loop is more performant than a while loop (see #56492)
52+
# This unrolls the loop a second time before entering the body
53+
for x in Iterators.rest(itr, y[2])
54+
v = op(v, x)
5555
end
5656
return v
5757
end

0 commit comments

Comments
 (0)