-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
<: vs === speed for types #30125
Comments
Why is that non-intuitive? |
Oh, well that makes sense. |
Though shouldn't |
It has that fast path already. The linked comments also seem to be primarily about inference. It is also expected that |
I mean I might have mis-titled the issue, maybe I should re-title it to |
Maybe; a test case would still be very helpful. Is there really a case where we can infer === (implying we know the exact structure) but not <: ? The other way is of course possible since === is strictly more precise. |
Maybe @nalimilan can provide the test case? My attempt to make up a test case (based on the comment above) didn't really pan out. julia> using BenchmarkTools
julia> unstable(x) = x ? 0 : missing
julia> input = map(unstable, rand(Bool, 1000))
julia> @btime map(x -> x isa Int || typeof(x) === Int, input);
1.199 μs (2 allocations: 1.08 KiB)
julia> @btime map(x -> x isa Int, input);
1.199 μs (2 allocations: 1.08 KiB) |
I don't know, the only situation where I know this mattered (when I wrote that comment at least), was in the implementation of |
Ok, so here's my own inexpert attempt to benchmark: using BenchmarkTools
import Base: Generator
import Base.Iterators: Filter
unstable(x) = x ? 0 : missing
input = rand(Bool, 1000000)
size_known = Generator(unstable, input)
size_unknown = Generator(unstable, Filter(x -> rand(Bool), input)) Then here's how I hacked Base: import Base: grow_to!, collect_to!, promote_typejoin
function grow_to!(dest, itr, st)
T = eltype(dest)
y = iterate(itr, st)
while y !== nothing
el, st = y
S = typeof(el)
if S <: T
push!(dest, el::T)
else
new = sizehint!(empty(dest, promote_typejoin(T, S)), length(dest))
if new isa AbstractSet
# TODO: merge back these two branches when copy! is re-enabled for sets/vectors
union!(new, dest)
else
append!(new, dest)
end
push!(new, el)
return grow_to!(new, itr, st)
end
y = iterate(itr, st)
end
return dest
end
function collect_to!(dest::AbstractArray{T}, itr, offs, st) where T
# collect to dest array, checking the type of each result. if a result does not
# match, widen the result type and re-dispatch.
i = offs
while true
y = iterate(itr, st)
y === nothing && break
el, st = y
if el isa T
@inbounds dest[i] = el::T
i += 1
else
R = promote_typejoin(T, typeof(el))
new = similar(dest, R)
copyto!(new,1, dest,1, i-1)
@inbounds new[i] = el
return collect_to!(new, itr, i+1, st)
end
end
return dest
end This is just the code from Base with the Then here are my benchmarks: # BEFORE
julia> @btime collect(size_unknown);
4.699 ms (19 allocations: 1.13 MiB)
julia> @btime collect(size_known);
471.802 μs (3 allocations: 879.09 KiB)
# AFTER
julia> @btime collect(size_unknown);
4.517 ms (19 allocations: 1.13 MiB)
julia> @btime collect(size_known);
452.055 μs (3 allocations: 879.09 KiB) So, I don't see any difference, but I'm not sure if I did this right |
Ok, here's another one, same as above except: input = trues(1000000)
input[1000000] = false
# BEFORE
julia> @btime collect(size_unknown);
18.435 ms (20 allocations: 5.00 MiB)
julia> @btime collect(size_known);
11.666 ms (7 allocations: 16.21 MiB)
# AFTER
julia> @btime collect(size_unknown);
19.714 ms (20 allocations: 5.00 MiB)
julia> @btime collect(size_known);
7.885 ms (4 allocations: 16.21 MiB) |
Thanks! So there would be a difference only for |
Which difference are you looking at? The only one that struck me was the reduction in allocations for size_known in the second case. Which suggests that removing |
I haven't looked into it yet, but that's entirely possible --- |
The specific shape of that expression also acts as an inference barrier (the |
Yup I'm officially lost now |
For reference (maybe a bit off-topic), |
I just had an example (JuliaFolds/Transducers.jl@6d99ccf) that changing |
@tkf - could you make a branch with the code that takes too long to compile and provide instructions to reproduce that? |
@JeffBezanson Rather than hijacking this issue, I posted a new one here: #30744 |
It looks like
===
is (non-intuitively) a lot faster for types, going back at least far as d194625 and as also discussed here #25828 (comment) and here #30076 (comment)The text was updated successfully, but these errors were encountered: