<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">
P.S.
<div class=""><br class="">
</div>
<div class="">Here’s something that might be of interest to those interested in the theory re inversion of control. The reason we know that synchronous and asynchronous code are “algorithmically equivalent”, i.e. able to express (using different syntax) the
same algorithms is that it’s a special case of the continuation/monad equivalence proved in 1994 (<a href="https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.43.8213" class="">https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.43.8213</a>).</div>
<div class=""><br class="">
</div>
<div class="">However, to make things more concrete (and hopefully, more widely understandable), consider that what delimited continuations do is turn a subroutine call into a subroutine return. In particular, in the JDK implementation, a call to Continuation.yield()
becomes a return from the call to Continuation.run(), and the call to Continuation.run() turns into a return from the call to Continuation.yield(). So we can turn any decision as to which (callback) subroutine to call into a decision on which subroutine to
return from.</div>
<div class=""><br class="">
</div>
<div class="">The asynchronous programming style is a special case of what’s known as a continuation-passing style, or CPS, where we register a callback with an operation, and the operation then decides when to call the callback (“inversion of control”). With
delimited continuations, and, with minor changes, threads, the registration of the callback becomes a call to yield, and the invocation of the callback becomes the *return* from yield.</div>
<div class=""><br class="">
</div>
<div class="">Making this even more concrete, in the async style we have a set of registered callbacks which we then call at will, whereas in the synchronous style we have a set of blocked threads which we then unblock at will. Calls into a callback become
returns from blocking calls.</div>
<div class=""><br class="">
</div>
<div class="">There is one difference which I papered over, which is that threads aren’t delimited continuations, but are essentially delimited continuations with an associated scheduler, so where in the async or delimited continuation cases, the “framework”
has control over scheduling, with threads, the thread scheduler has control over scheduling. In practice, that is a second-order concern for the intended use-case of threads, but we can close that gap with pluggable thread schedulers (that are being worked
on but were not delivered in JEP 425).</div>
<div class=""><br class="">
</div>
<div class="">— Ron<br class="">
<div><br class="">
<blockquote type="cite" class="">
<div class="">On 21 Jul 2022, at 12:42, Ron Pressler <<a href="mailto:ron.pressler@oracle.com" class="">ron.pressler@oracle.com</a>> wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">
<br class="">
<div class=""><br class="">
<blockquote type="cite" class="">
<div class="">On 20 Jul 2022, at 19:49, Alex Otenko <<a href="mailto:oleksandr.otenko@gmail.com" class="">oleksandr.otenko@gmail.com</a>> wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<div dir="auto" class="">Waiting for requests doesn't count towards response time. Waiting for responses from downstream does, but it is doable with rather small thread counts - perhaps as witness to just how large a proportion of response time that typically
is.</div>
</div>
</blockquote>
<div class=""><br class="">
</div>
<div class="">I am not talking about what’s *doable* but about what virtual-thread programs *do* (or can do), i.e. use a thread to wait for a response. As I made very clear, this can also be done using async APIs, which were invented for the very same reason
(get around the maximum thread count limitation), but then you’re missing out on “harmony” with the Java platform, which knows about threads and not async constructs.</div>
<br class="">
<blockquote type="cite" class="">
<div class="">
<div dir="auto" class="">
<div dir="auto" class=""><br class="">
</div>
<div dir="auto" class="">I agree virtual threads allow to build things differently. But it's not just the awkwardness of async API that changes. Blocking API eliminates inversion of control and changes allocation pattern.</div>
</div>
</div>
</blockquote>
<div class=""><br class="">
</div>
<div class="">I disagree, but no one is taking async APIs away. If you enjoy programming in that style, you’re more than welcome to continue doing so.</div>
<br class="">
<blockquote type="cite" class="">
<div class="">
<div dir="auto" class="">
<div dir="auto" class=""><br class="">
</div>
<div dir="auto" class="">For example, first you allocate 16KB to read efficiently, then you are blocked - perhaps, for seconds while the user is having a think. So 10k connections pin 160MB waiting for a request. With async API nothing is pinned, because you
don't allocate until you know who's read-ready. This may no longer be a problem with modern JVMs, but needs calling out.</div>
</div>
</div>
</blockquote>
<div class=""><br class="">
</div>
<div class="">That is incorrect. A synchronous API can allocate and return a buffer only once the number of available bytes is known. There is absolutely no difference between asynchronous and synchronous APIs in that respect. In fact, there can be no algorithmic
difference between them, and they can both express the same algorithm. The difference between them is only how an algorithm is *expressed* in code, and in which constructs have built-in observability support in the runtime.</div>
<br class="">
<blockquote type="cite" class="">
<div class="">
<div dir="auto" class="">
<div dir="auto" class=""><br class="">
</div>
<div dir="auto" class="">The lack of inversion of control can be seen as inability to control who reads when. So to speak, would you rather read 100 bytes of 10k requests each, or would you rather read 10KB of 100 requests each? This has impact on memory footprint
and who can make progress. It makes sense to read more requests when you run out of things to do, but doesn't make sense if you saturated the bottleneck resource.</div>
</div>
</div>
</blockquote>
<div class=""><br class="">
</div>
There is no difference between synchronous and asynchronous code here, either; they just express what it is that you want to do using different code. If you want to see that in the most direct way, consider that the decision of which callback to call and the
decision on which thread waiting on a queue you want to unblock and return a message to is algorithmically the same.</div>
<div class=""><br class="">
</div>
<div class="">There is nothing that you’re able to do in one of the styles and unable in the other. In terms of choice, there’s the subjective question of which style you prefer aesthetically, and the objective question of which style is more directly supported
by the runtime and its tools.</div>
<div class=""><br class="">
</div>
<div class="">— Ron</div>
</div>
</div>
</blockquote>
</div>
<br class="">
</div>
</body>
</html>