<div dir="auto">There is an important difference between synchronous API with semaphores, blocking queues, etc and reactive API with backpressure.<div dir="auto"><br></div><div dir="auto">The difference is that reactive API is essentially continuation passing, one important aspect of which is the inversion of control. ("Don't call us, we'll call you") Whereas there is a known isomorphism between the two models of computation, the complexity of expression differs. My stock example where continuation passing is much simpler is the tree iterator vs the generator for a tree.</div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">Alex</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 21 Jun 2022, 14:11 Brian Goetz, <<a href="mailto:brian.goetz@oracle.com">brian.goetz@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
<font size="4"><font face="monospace">"Backpressure" is just a fancy
new term for the age-old concept of bounding resource
utilization by stalling or refusing excessive requests.
Examples include: <br>
<br>
- thread pools -- limit the number of concurrently executing
tasks<br>
- semaphores -- limit the number of a critical resource (socket
connections, open files, etc), by stalling incremental requests
until the resource becomes free<br>
- producer/consumer with blocking queues -- when consumers are
overloaded, stall the producers<br>
- queuing of socket connect requests in the OS, and refusing
additional requests after the queue gets too long<br>
- various networking flow control protocols using send credits,
sliding windows, etc (xmodem, TCP)<br>
<br>
These are often used in conjunction; a thread pool may have a
fixed number of threads *and* a bounded queue for waiting
tasks. OSes queue socket requests until some limit, and then
refuse incremental requests. These are all techniques of slowly
pushing the load back to the source. <br>
<br>
But, backpressure is not magic; it still requires analysis and
control. Before you can use it effectively, you have to
identify what the resources are that might get over-consumed,
and choose a strategy for managing it. Obvious strategies
include "don't call me, I'll call you", queue size limits, etc.
But none of these are applied magically; they require you to
configure them. Reactive's contribution, such as it is, is to
put these concepts in the foreground, where users are reminded
to think about them. <br>
<br>
All of these techniques are still available to us. But we have
to identify what resources are in danger of being overconsumed,
and protect them appropriately. The concepts for doing so are
older then Java -- semaphores, blocking queues, etc. <br>
</font></font><br>
<div>On 6/20/2022 2:33 PM,
<a href="mailto:eric@kolotyluk.net" target="_blank" rel="noreferrer">eric@kolotyluk.net</a> wrote:<br>
</div>
<blockquote type="cite">
<div>
<p class="MsoNormal"><span lang="EN-US">After tinkering with
loom and learning a lot of revised synchronous style
practices, I was recently watching another presentation on
Reactive Programming, and it got me thinking about how some
of the asynchronous practices, such as Backpressure, could
be expressed in the synchronous world of Virtual Threads,
Structured Concurrency, etc.<u></u><u></u></span></p>
<p class="MsoNormal"><span lang="EN-US"><u></u> <u></u></span></p>
<p class="MsoNormal"><span lang="EN-US">After working on Akka
Scala for years, using Reactive Practices, I had a sense
that it might be possible to build applications/services
that would not thrash. They would go up to 100% utilization,
without thrashing, and then just refuse more work. <i>Sorry
mate, I won’t do that now, maybe talk to the Load Balancer
about spawning some more siblings…</i> I don’t know how
true this sense is, only that it’s a hopeful sense.<u></u><u></u></span></p>
<p class="MsoNormal"><span lang="EN-US"><u></u> <u></u></span></p>
<p class="MsoNormal"><span lang="EN-US">While I have dabbled
with </span>java.util.concurrent.Flow using Virtual Threads
successfully, I still find the cognitive load for using Rx
APIs higher than I would like, but it is well disciplined and
has many other benefits, such as backpressure.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">In the future, can we build simpler
synchronous APIs with the benefits of asynchronous APIs such
as Rx, leveraging the scalability/throughput of Virtual
Threads and the discipline of Structure Concurrency? I guess I
am just lazy, and I don’t want to think harder than I have to.<u></u><u></u></p>
<p class="MsoNormal"><u></u> <u></u></p>
<p class="MsoNormal">Cheers, Eric<span lang="EN-US"><u></u><u></u></span></p>
</div>
</blockquote>
<br>
</div>
</blockquote></div>