-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Some transducers (e.g. Cat) do internal reductions inside of their next methods. For example,
upstream Transducers.jl does
struct Cat <: Transducer
end
function next(rf::R_{Cat}, acc, x)
rf0, itr0 = retransform(inner(rf), asfoldable(x))
return __foldl__(skipcomplete(rf), acc, itr0)
endwhich basically says that foldl(+, Cat(), [[1.0,2.0,3.0], [4.0, 5.0]]; init=0.0) should turn into
acc = 0.0
for v in [[1.0,2.0,3.0], [4.0, 5.0]]
for x in v # <------ The inner fold performed by `Cat`
acc += x
end
endHowever, I have been wanting to make whether or not SIMD is enabled an Executor option, and I wanted to pass Executors to __fold__ and dispatch on them. But this creates a problem for things like Cat(), because it means they might lose things like their SIMD execution info.
There's three potential fixes I see here:
- Make executors transducers. Upstream
Transducers.jlactually does this withSIMDalready, but it doesn't do it with things like threads or distributed. I don't think I like this because it's not really a transformation of the inner reducing function, and it's also messy to use / support. - Make
Cat()hold an Executor. E.g. this would mean you'd writefold(+, Cat(executor = SIMDEx()), vov)if you wanted SIMD to be applied in the inner loop. There's some times where this would be nice and make sense, but I think most of the time it'd just be kinda annoying because it'd case a lot of passing around executors.- One place this is nice would be that you could write something like
fold(+, Cat(executor=ThreadsEx()), vov)to do inner parallelism. I'm not sure how I feel about this though.
- One place this is nice would be that you could write something like
- Make
nexttake an executor option. So this means that instead of havingnext(rf, acc, x)you'd havenext(rf, acc, x, executor), where theexecutorargument is normally just ignored, but transducers likeCatcan forward it to their inner reduction steps.
I think I dont like option 1, and I'm a little unsure about options 2/3. They both have upsides and downsides. We could also do both of 2 and 3, since they're compatible, i.e. if Cat isn't given an executor, then Cat will use the provided one inside of next.