Hi everyone and happy new year.
To push the thinking a but further on that matter, I've implemented a version of broadcast
based on a buffering strategy.
Let me know what you think.
Hi everyone and happy new year.
To push the thinking a but further on that matter, I've implemented a version of broadcast
based on a buffering strategy.
Let me know what you think.
Coming back to this after the holidays now. I agree that there are multiple different behaviours; however, I believe we should start with the "consume at the speed of the fastest consumer including a buffer". This is to me the safest option. If we realise that further down the line we want the other one we can always create that and provide an option for it.
The option you laid out without back pressure is basically just a buffer
attached to the upstream and a "fastest consumer" strategy. So I wouldn't spend any time on that.
W.r.t. to "Subjects" I would like to see how the ecosystem evolves once we get broadcast
, because as you said, you can compose an AsyncStream
and broadcast
to get the desired behaviour. From my experience "Subjects" have sometimes lead to confusion so maybe a more explicit composition is good.
My point is that perhaps this is something we should consider holistically.
Subject's may appear complex on the surface, but perhaps that's because they solve multiple problems in a single-shot:
AsyncSequence
types to be multi-cast)AsyncSequence
issueMy concern is that if we continue down the path of solving only no. 2, we will slowly move away from solving no. 1 and no. 3.
My opinion is that there seems to be an attachment to the API of AsyncStream
, and particularly breaking apart the 'producer' and 'sequence' parts, similar to the discussion about enhancing AsyncStream
with a new initialiser, in the name of simplicity. However, the alternative seems to be many more types with limited composability. So far, I'm not sure this is a progression of the benefits provided by a Subject
like type, and to me it feels even more complex.
For example, now programmers must remember that they always need to chain a broadcast
sequence to their asynchronous sequence pipelines if they wish to vend to an unknown number of consumers. Worse, if the sequence is type erased (any AsyncSequence
), they'll need to do this defensively to avoid undefined behaviour.
Of course, a Subject
equivalent would need to be carefully designed to leverage the unique properties of AsyncSequence
(i.e. autoconnect
doesn't make much sense in the context of a back pressure supporting pipeline), but on the whole, my guess is the surface complexity of Subject will result in a net reduction in complexity when viewed holistically and compared to the current direction.
Hope this is helpful – happy to discuss any of the points raised in further detail if useful.
Is there any traction on this?
After wwdc I was hoping to see async algorithms bring more feature parity to what Combine offers but it doesn't seem like it is happening any time soon and your post was the only thing going in that direction. Are there any initiatives for this to be taken into consideration or to produce solutions which tackle the problems you are trying to solve here?
Thank you for your effort btw :)
I agree, progress on asynchronous sequences does appear to have slowed down somewhat.
I don't have any particular insights into why, but my guess would be that we're dependent on decisions in other areas of the language before AsyncSequence
can really get into a good shape. For example, a decision on typed throws will determine the shape of a protocol for production side of an AsyncSequence
– an AsyncSource
or whatever it ends up being called. It would also allow for primary associated types to be locked-in for AsyncSequence
, or failing that whether a stop-gap AnyAsyncSquence
type should have 1 generic parameter, or include a 2nd parameter for a typed error.
More widely, I'm not sure asynchronous sequences can ever be a complete replacement for Combine as the focus for asynchronous sequences is decidedly on the asynchronous part. Probably quite rightly, It's very hard to wrestle Swift concurrency into acting synchronously as has been discussed quite extensively on the Observable proposal.
Maybe, Observable
will eventually fill much of this particular gap, but that remains to be seen.
Observation has taken a lot of my time to get that over the line - broadcast is definitely one of the first post 1.0 things to tackle.
Things that need to be done:
Is there any chance to get a rough estimated timeline on when a 1.0 can be expected and when things like broadcast will have a decision which path to take?
The faster we can get some of those issues I pointed out addressed the quicker we can start to work on those other parts.
I have a couple of PRs up for some of them -
But truth be told there are bits that folks could help out getting those done faster. Reviews definitely are useful, also confirmation of testing of those changes. Additional audits of inlines, sendability and warnings will go a long way to shoring up the remaining bits.
With Async Algorithm 1.0 released in December last year, what is the status on getting Broadcast / Shared / Multicast implemented in Async Algorithm package? Anything being worked on?
I also have this need for my applications. Pending this feature request landing... what would be the best alternative APIs to use today for a multicast Pub/Sub like component?
I'm bringing this back as probably many of us are waiting for the final implementation.
Based on already proposed solutions in chronological order:
& potential vision from @FranzBusch Broadcast algorithm (Previously Shared) by tcldr · Pull Request #227 · apple/swift-async-algorithms · GitHub
Can we consider the last one as the closest desired solution to the problem until the final solution is released?
I’ll jump in here to say I haven’t been actively developing my own ideas on this further, but I still firmly believe that the ideal solution to this looks quite a bit different to those above.
The crux of it is that the range of problems that this algorithm should attempt to solve is broader than a single algorithm.
Firstly, as you begin designing a multicast algorithm such as the one above, it becomes clear that there are many variations on a 'broadcast' algorithm, and therefore it's important that we design a solution to accommodate future enhancements.
The following comment by @ktoso summarises some of these:
Secondly, and perhaps more contentiously, I'm still unclear as to why this family of broadcast algorithms is expected to be chained (like map
or filter
) rather than being source algorithms (like AsyncStream
or Subject's in the Rx/Combine world.)
The argument that I've heard to date is that programmers will find the 'chaining' algorithms simpler to understand as they struggle with the concept of Subjects in Rx/Combine.
However, I think that this is to miss some of the benefits of this model.
One of the big things that I think new programmers struggle with is that they are unable to iterate over source sequences (such as AsyncStream) multiple times – they're 'single shot'. Concerningly, the behaviour when you do is undefined.
If we were to instead adopt the source algorithm approach to multicasting, we would benefit from not only a range of multicasting options, but also a range of source algorithms that can safely be iterated multiple times. (And also designed to accommodate other issues such as back pressure.)
Of course, this approach would take some design effort, likely the introduction of a new AsyncSource
type (roughly equivalent to a Subject) in the stdlib and then a new chained operator to multicast via said AsyncSource types. But I think it would go a long way to solving many of the shortcomings we have with AsyncSequence today.