Virtual Threads: A Short Note about Naming

Ron Pressler ron.pressler at oracle.com
Sun Nov 24 22:46:51 UTC 2019


Knowing the many flavours of continuations is not at all necessary to 
understand Loom's continuations, let alone threads, but since you asked:

* Asymmetric: When the continuation suspends or yields, the execution returns to
  the caller (of Continuation.run()). Symmetric continuations don't have the
  notion of a caller. When they yield, they must specify another continuation to
  transfer the execution to. Neither symmetric nor asymetric continuations are
  more powerful than one another, and each could be used to simulate the other.
  
* Stackful: The continuation can be suspended at any depth in the call-stack,
  rather than in the same subroutine where the delimited context begins when the
  continuation is stackless (as is the case in C#). I.e the continuation has its
  own stack rather than just a single subroutine frame. Stackful continuations are
  more powerful than stackless ones.
  
* Delimited: The continuation captures the execution context that starts with a
  specific call (in our case, the body of a certain runnable) rather than the
  entire execution state all the way up to main(). Delimited continuations are
  strictly more powerful than undelimited ones (http://okmij.org/ftp/continuations/undelimited.html), 
  the latter considered "not practically useful" (http://okmij.org/ftp/continuations/against-callcc.html).
  
* Multi-prompt: Continuations can be nested, and anywhere in the call stack, any
  of the enclosing continutions can be suspended. This is similar to nesting of
  try/catch blocks, and throwing an exception of a certain type that unwinds the
  stack up to the nearest catch *that handles it* rather than just the nearest
  catch. An example of nested continuations can be using a Python-like generator
  inside a virtual thread. The generator code can do a blocking IO call, which
  will suspend the enclosing thread continuation, and not just the generator: 
  https://youtu.be/9vupFNsND6o?t=2188
  
* One-shot/non-reentrant: Every time we continue a suspended continuation its
  state is mutated, and we cannot continue it from the same suspension state
  multiple times (i.e we can't go back in time). This is unlike reentrant
  continuations where every time we suspend them, a new immutable continuation
  object that represents a particular suspension point is returned. I.e. the
  continuation is a single point in time, and every time we continue it we go back
  to that state. Reentrant continuations are strictly more powerful than
  non-reentrant ones; i.e. they can do things that are strictly impossible with
  just one-shot continuations.
  
* Cloneable: If we are able to clone a one-shot continuation we can provide the
  same ability as reentrant continuations. Even though the continuation is mutated
  every time we continue it, we can clone its state before continuing to create a
  snapshot of that point in time that we can return to later.
  

- Ron



On 23 November 2019 at 21:42:48, Volkan Yazıcı (volkan.yazici at gmail.com(mailto:volkan.yazici at gmail.com)) wrote:

> Ron, really appreciated your elaborate answer. I will go further and kindly ask you to shed some light into certain terms you used in your explanation. Regarding the following paragraph:
>  
> > ... one-shot (non-reentrant) delimited continuations, and,
> > at least in the past, they were sometimes used to refer to  
> > *symmetric* one-shot delimited continuations, although they
> > have been used to refer to assymetric delimited continuations
> > as well. The continuations used under the cover to implement
> > Loom's virtual threads are multi-prompt, one-shot -– although
> > possibly cloneable -- stackful, assymetric, ...
>  
> Would you mind explaining what do you exactly mean by  
> one-shot,
> non-reentrant,
> delimited,
> symmetric & asymmetric,
> multi-prompt,
> cloneable,
> stackful,
>  
> please? (Additional references are more than welcome.) I definitely have some guesses and Google'd them, but aligning to your perspective, I believe, would help many others in the list, including me.
>  
> Best.
>  
> On Fri, Nov 22, 2019 at 12:24 PM Ron Pressler wrote:
> > Loom’s virtual threads are not coroutines under any common definition of that
> > name. Coroutines are one-shot (non-reentrant) delimited continuations, and, at
> > least in the past, they were sometimes used to refer to *symmetric* one-shot
> > delimited continuations, although they have been used to refer to assymetric
> > delimited continuations as well. The continuations used under the cover to
> > implement Loom's virtual threads are multi-prompt, one-shot -– although possibly
> > cloneable -- stackful, assymetric, delimited continuations (yeah, continuations
> > come in many flavors). It is possible we'll decide to call those continuations
> > coroutines, although in recent years the name coroutines gained a connotation
> > that identifies it with a particular implementation of continuations as special
> > syntactic constructs in the language (such as async in C# or suspend in Kotlin).
> > But in any event, coroutines always refer to continuations (Go's goroutines, a
> > pun on coroutine, does refer to threads).
> >  
> > Threads are a continuation plus a scheduler, or scheduled continuations, and
> > therefore Loom's user-mode threads are threads, and whether or not we decide to
> > call Loom's continuations coroutines, the name is inappropriate for scheduled
> > entities.
> >  
> > The name is not only technically inappropriate, but suffers from all the same
> > problems "fiber" does, and then some. It sounds like a whole new concept people
> > have to learn, it is heavily overridden elsewhere to refer to somewhat similar,
> > yet substantially different, concepts, and it doesn't even evoke a conceptual
> > similarity to threads.
> >  
> > As to your two questions, I'll address them more specifically inline, below:
> >  
> >  
> >  
> > On 22 November 2019 at 08:47:13, Volkan Yazıcı (volkan.yazici at gmail.com(mailto:volkan.yazici at gmail.com)(mailto:volkan.yazici at gmail.com)) wrote:
> >  
> > > As someone who is far from comprehending the implications of concluding on a certain nomenclature for Project Loom deliverables, I am having difficulty in understanding why don't we just call "this" as "coroutines". In a discussion between you and Jonathan Brachthäuser(http://mail.openjdk.java.net/pipermail/loom-dev/2018-September/000141.html), you had shared some more insight into the reasoning behind the back then naming conventions. There you had also hinted that you may decide to change the name to "coroutine". Regarding this and the aforementioned discussion, I have two questions:
> > > In statement "more recently [coroutine] has gained the connotation (not in academic literature but in language implementations) of being a syntactic construct, rather than a purely dynamic one" of yours, would you mind elaborating on what do you exactly mean by a "purely dynamic one"? I see that C++20 and other coroutine-providing PLs require explicit syntactic sugar to denote suspendable-and-resumeable subroutines. But apart from this explicit denotation requirement, isn't Loom delivering almost the same thing? Further, Loom also enforces its own explicit requirements (i.e., subroutine needs to be wrapped in a "virtual thread"), which "feels" similar to me from a developer perspective.
> >  
> > That explicit syntactic denotation is no small matter. It is the reason languages
> > with that kind of continuations cannot unify the concept of suspension and blocking
> > even though the only difference between the two is whether suspension is implemented
> > by operating system or by the language. A language like, say, JavaScript needs two  
> > separate IO APIs, one blocking and one suspending, or asynchronous, even though the
> > two may have the exact same denotation in the language. Languages like C#, Rust and
> > Kotlin even separate the two in the type system. That in Java suspending a continuation
> > does not require any different type, or any other syntactic notation whether the
> > operation is performed by the kernel or the language is an essential feature. So the
> > languages I mentioned syntactically separate a concept based on its particular  
> > implementation, but Java (like Erlang, Scheme and Go) doesn’t. Loom's virtual threads
> > *are* threads; why focus on the implementation rather than the abstraction especially
> > when we don’t make any syntactic distinction between them?
> >  
> > > To the best of my knowledge, Melvin Conway's 1958 definition of "coroutines" basically boils down to good old subroutines with suspend and resume support. From this angle, I feel inclined to call Loom "virtual threads" as "coroutines". The latter term might indeed be tainted by modern times, but I believe Java has enough leverage and resources to rinse it off. This will also imply a PR for Java in the sense of "better coroutines" addressing all the catches and limitations imposed by, say, Kotlin, Quasar, Kilim "coroutines”.
> >  
> > As I said above, Loom’s threads are not coroutines, but coroutines + scheduler. The
> > common name for coroutines + scheduler, for many years, has been "thread."
> >  
> > > Best regards.  
> > >  
> > > P.S. Thanks for updating the community on these internal changes and letting us get engaged in discussions.
> >  
> >  
> > - Ron
> >  
> > >  
> > > On Thu, Nov 21, 2019 at 1:07 PM Ron Pressler wrote:
> > > > We started with fibers. Then we found out that people think it's a new concept
> > > > they have to learn (which is further complicated because "fiber" is used to
> > > > refer to superficially-similar-yet-essentially-different concepts elsewhere)
> > > > rather than just a user-mode implementation of threads. The different name then
> > > > became even less justified when we started representing our user-mode threads as
> > > > java.lang.Thread. We then considered "lightweight threads." The problem with
> > > > giving an absolute name to a relative concept is that one day we may have
> > > > threads that are even lighter-weight than lightweight threads, and what would we
> > > > call those? "User-mode threads" is correct but perhaps too technical. So we're
> > > > going with "virtual threads." The name is intended to evoke the similarity of
> > > > the relationship our usermode threads have with kernel threads to that between
> > > > virtual and physical memory. The name has the advantage of familiarity on one
> > > > the one hand as well as not clashing with potentially confusing
> > > > similar-but-not-quite usages on the other. A test run of "virtual threads" at
> > > > Devoxx looked promising.
> > > >  
> > > > - Ron
> > > >  
> > > >  
> >  



More information about the loom-dev mailing list