5 ms·
availableToPoll() is the method that blocks, because it can return 0 on an empty ring. When that happens you have to block, by for example busy spinning around
by joas_coder 2y ago
availableToPoll() is the method that blocks, because it can return 0 on an empty ring. When that happens you have to block, by for example busy spinning around availableToPoll() until it returns something to poll.
You are never supposed to call poll() without first calling availableToPoll(). How can you poll something if you don't know if there is something available to poll? This is very different than a ConcurrentLinkedQueue where you can call poll() on an empty queue and get a null to indicate that the queue is empty. Also because the ring is a circular queue, you have to know what you can safely poll before polling. That's all done through availableToPoll().
NOTE: By garbage here I don't think you are talking about GC garbage.
- gpderetta 2y ago> How can you poll something if you don't know if there is something available to poll counterexample: you can call ::poll(2) if there isn't anything to available. It will either block or return as desired. That's literally what I would expect a poll function to do: check if something is available; c.f. busy-polling. Maybe it is a language difference?
- joas_coder 2y agoNot a language difference, but a design difference. By calling availableToPoll before polling you can poll a batch of messages without blocking or locking on each message. This design decision allows the ring to perform batching naturally. And batching is very important for perfomance. java.util.concurrent.ConcurrentLinkedQueue does not support batching.
- knome 2y agoI don't think anyone is questioning the strategy, just the naming. Polling, as a term, already generally means asking if there is anything ready. The library might instead have had a poll() to indicate readiness and an unsafeTakeReadyBatch()/releaseBatch() or similar to handle the low level receipt primitives. Or you could even have had a checkForReady() and left poll() to implement a generic version of your busy waiting example, polling with a given sleep and timeout until items were ready, as a convenience for the user. It's fine as is, of course, as you document expected usage quite well.
- joas_coder 2y agoOh, I see now. I thought he was talking about a computer language but he was actually talking about the English language. My bad. So are you saying that POLL was a bad choice of name because polling means "check if there is something available and if there is get it"? What would be a better name? How about availableToFetch and fetch? Any other better idea? I don't like remove because you are not actually removing the object from the ring.
- gpderetta 2y agopoll doesn't necessarily imply removing.
- joas_coder 2y agoIt is clear to me now that poll only removes if there is something to remove A much better name would have been FETCH and not POLL We'll be changing everything from poll to fetch in the next version => availableToFetch() and fetch()
- gpderetta 2y agoWhile we are bikeshedding, what about peek() (returns the element, but doesn't dequeue), pop() (dequeue and return the element), try_peek(), try_pop() for the polling variants.
- joas_coder 2y agoThis change is now released. Thanks knome and gpderetta for your suggestions and clarifications. availableToPoll() is now availableToFetch() poll() is now fetch() peek() is now fetch(false) Note that fetch() == fetch(true)
- kllrnohj 2y ago> availableToPoll() is the method that blocks, because it can return 0 on an empty ring. Which means it doesn't block... Blocking means the call itself doesn't return until there's data available. This is a completely non-blocking API. Which is fine, it's just very wrongly named in that case. But that also means I don't really know why there's both "non-blocking" and "blocking" variants at that point if blocking isn't an option at all in the first place.
- joas_coder 2y agoYou are going to block/wait yourself when availableToPoll() (now changed to availableToFetch() for clarity) returns 0. When that happens you can block/wait by busy spinning or by using a wait strategy. The blocking term means that the producer has to block/wait when the ring is full and the consumer has to block/wait when the ring is empty. For the non-blocking ring, the producer never blocks on a full ring. It overwrites the circular ring. The consumer can still block on an empty ring. So to make it clear: Blocking ring => producer and consumer can block/wait Non-Blocking ring => producer never blocks and consumer can still block on an empty ring. Consumer can also fall behind too much and disconnect.