Comments (24)
Combine for example used the rule for throttle and debounce: that the iterative output (not the signals to determine failure or finishedness) are the rate limited things. So specifically for throttle; it means that even the last value should not emit any faster than the requested throttling rate.
The intent for folks using throttle is that they don't ever want a rate beyond a given value. Making the last value ignore that would break folks expectations.
from swift-async-algorithms.
We can definitely have a latest: true
option here. The implementation should also be quite trivial, if we get nil
from the upstream and we have a last
value and latest = true
then we can do a Task.sleep
until the timeout has passed.
I'm fairly certain the current debounce implementation will not emit the final value in all cases.
If that happens and you can reproduce it please open a separate issue here.
from swift-async-algorithms.
I should add, I guess it's the "penultimate" value I'm looking for - I realize that nil
is the final value in a "finished" AsyncStream
from swift-async-algorithms.
Is it a throttle with “latest” ? If not then it can be normal that the penultimate element is skipped.
from swift-async-algorithms.
Is it a throttle with “latest” ? If not then it can be normal that the penultimate element is skipped.
Yes, latest = true, just calling let throttledStream = stream.throttle(for: .seconds(1), latest: true)
, for example.
from swift-async-algorithms.
Keep in mind that AsyncSequence is a pull mechanism whereas Combine is a push mechanism for instance. It means that the throttling is applied to the pace of the consumer, not the producer.
in your case, let’s say you have a throttling duration of 1s, here is what I suspect is happening at the end of the timeline:
|
| x -> last received element by the consumer, a new throttling start time is set, ending in 1s
| y -> new element is discarded because it is too close to ‘x’ (the time elapsed since the start is < 1s)
|
| z -> last element is discarded because it is too close to ‘x’ (the time elapsed since the start is < 1s)
|
| nil -> the upstream sequence is finished before the theoretical end of this throttling session
|
| ——> theoretical end for the current throttling session (start + 1s)
V
In the end the consumer doesn’t receive the penultimate element but the last that matches a throttling session’s end, that is to say ‘x’.
I hope this helps. @FranzBusch could also chime in to confirm or not (he made the algorithm I think).
from swift-async-algorithms.
Yes, this behavior makes sense to me, but I think it might be nice to find a way to always get the penultimate value somehow... Would a PR be welcome for this?
from swift-async-algorithms.
Yeah I can see how that would be useful. Let’s say you throttle a text field (like a search field), with the current implementation you would not have the last character … which would be wrong search wise.
@FranzBusch what’s your take on that ? Should we switch to another implementation that:
- iterate over the upstream sequence in a dedicated Task and push the values into a “Throttle” state machine
- run a “tick” periodically in a dedicated task and push each “tick” into the “Throttle” state machine
- for every “tick” use the “Throttle” state machine to retrieve the appropriate value and push it into a kind of “unicast buffered state machine”
- expose the “unicast buffered state machine” to the consumers
It would be much closer to what throttling does in push based system … but with the drawback of not be based on the consumer pace.
from swift-async-algorithms.
Couldn't we just change the implementation of throttle
to check if there is a latest value when the upstream returns nil
and then return the latest value. IMO we could also make this the default but would like to get @phausler on this as well.
from swift-async-algorithms.
Couldn't we just change the implementation of
throttle
to check if there is a latest value when the upstream returnsnil
and then return the latest value. IMO we could also make this the default but would like to get @phausler on this as well.
That makes sense to me. Would the final value still be throttled or debounced at the specified interval, or would we break the contract for the "final" value?
from swift-async-algorithms.
That makes sense to me. Would the final value still be throttled or debounced at the specified interval, or would we break the contract for the "final" value?
Good question. I would like to understand what the current standard in other frameworks is. If we could get a little comparison going here that would be nice to make an informed choice.
from swift-async-algorithms.
@FranzBusch My initial thought would be to respect the specified throttle interval when deciding when to emit the final value.
from swift-async-algorithms.
It might be difficult to achieve with the current implementation since we have no way to determine that a value is the final value. We cannot postpone the emitting until the throttling duration is finished.
That's why I suggested to rely on a tick
mechanism but it makes things significantly more complex and changes the way the upstream sequence is being iterated over.
from swift-async-algorithms.
Thanks for clarifying the behaviour @phausler. I think that makes sense but it also means we will be dropping the final values in some cases which IMO is correct. If you throttle you have to live with the fact that you might be losing values which you are already due to the rate limiting.
from swift-async-algorithms.
@FranzBusch that wasn't how I interpreted @phausler's comment. I took it to mean we should always emit the final value, but only after the specified throttle interval has elapsed.
from swift-async-algorithms.
@FranzBusch it means that if you throttle a TextField you might loose the last value, which will be an issue when performing a search for instance.
from swift-async-algorithms.
no, I meant that the value is not expected to be emitted earlier than the interval, termination on the other hand is not a participant of that emission so therefore it can happen before the interval.
Per text fields; I think (just like other button presses) debounce is usually the right tool. Sadly we don't have any capacitors handy ;)
from swift-async-algorithms.
My issue is that I want to update the progress of a long running task, and would like to not miss the final "I'm at 100% complete" progress update ever, which seems like a fair request.
from swift-async-algorithms.
Per text fields; I think (just like other button presses) debounce is usually the right tool. Sadly we don't have any capacitors handy ;)
yep sure. I was just trying to illustrate my point with a real-life use case but I still think we should not be able to skip the last element since some use cases will rely on that.
from swift-async-algorithms.
no, I meant that the value is not expected to be emitted earlier than the interval, termination on the other hand is not a participant of that emission so therefore it can happen before the interval.
Per text fields; I think (just like other button presses) debounce is usually the right tool. Sadly we don't have any capacitors handy ;)
I'm fairly certain the current debounce implementation will not emit the final value in all cases.
from swift-async-algorithms.
Re: textfield search, not all cases you want to debounce. Throttling can be acceptable in certain use cases.
from swift-async-algorithms.
to be clear; it is reasonable to have opt-in behaviors or overloads of algorithms that adjust these fine points. I was just commenting on the behavior implemented for other systems.
from swift-async-algorithms.
@phausler just put up a PR #292 to change the behaviour. We would appreciate if you all could check that it is doing what you expected it to do now.
from swift-async-algorithms.
@phausler just put up a PR #292 to change the behaviour. We would appreciate if you all could check that it is doing what you expected it to do now.
Yes, this does exactly what I expect now!
from swift-async-algorithms.
Related Issues (20)
- Tests fail with the iOS simulator HOT 1
- Removed `Task.select(_:)` method is still called. HOT 3
- `Sequence`-based implementation of combining algorithms in addition to variadic ones HOT 1
- Provide an option for chunking based on a signal to include empty chunks
- Iterating `combineLatest`, `merge`, `zip` and `debounce` when Task is already cancelled HOT 1
- Several tests fail or hang on linux with the official trunk snapshot toolchains HOT 5
- Debounce does not yield values if rate is higher than the pace of the stream HOT 2
- Compiler crash in AsyncChannel HOT 1
- For `Void` element AsyncSequence types it might be nice to have a `waitForAll() async rethrows` similar to TaskGroup HOT 1
- `throttle` does not emit the latest element at interval occurrence when latest is `true` HOT 24
- `AsyncChunksOfCountSequence` does not create chunks of 1 element each. HOT 1
- Debounce silently swallows thrown errors and stalls iteration HOT 7
- Type erasure of AsyncSequences HOT 6
- Build warnings on Xcode 15/Swift 5.9 in AsyncBufferSequence.swift HOT 1
- How do I cancel async task when using AsyncChannel HOT 1
- Documentation for interspersed(with:) contains a bad link
- Debounce behaving weirdly in proposed unit test
- README and Guides are missing docs for `buffer(policy:)`
- No way to cancel `AsyncChannel` producer task when consumer task finishes early HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from swift-async-algorithms.