I have now read JEP 429 Extent-local variables (ELV) <https://openjdk.org/jeps/429>, which is probably the most salient for the discussion about context.Context.
ELV allow to "bind" values a variable in a way that is local to a (virtual) thread. Those values are AIUI not always inherited to child threads, but they *are* inherited when using StructuredTaskScope. ELV are immutable, but it is possible to create a new binding, forming a sort of "stack". Using x.get(), you can get the value bound in the topmost frame of that stack. This, of course, is exactly what context.WithValue/context.Context.Value does: It creates a stack of immutable bindings of values to "keys" (corresponding to the ExtentLocal instances) in a stack. Those bindings then propagate down the stack, but not up. The design document makes one argument in favor of TLS/ELV in favor of explicit argument passing: Normally, data is shared between caller and callee by passing it as method > arguments, but this is not viable for a Principal shared between the server > component and the data access component because the server component calls > untrusted user code first. We need a better way to share data from the > server component to the data access component than wiring it into a cascade > of untrusted method invocations. This, of course, is not a concern for context.Value. The key can simply be an unexported type, preserving the property that a context.Context does not give access to "private" state. So, in effect, we can find a rough correspondence between these new Java concurrency primitives and Go: - virtual threads correspond to goroutines - structured concurrency correspond to errgroup and the cancellation-aspect of context.Context - extent-local variables correspond to the value-aspect of context.Context The one difference remaining is that Go requires the explicit passing of a context.Context, while Java stores both of its aspects ultimately in TLS. AIUI, the Java side does not allow ELV to be inherited or passed to other threads, unless they are created as a sub-task using the structured concurrency primitive. Making that possible is exactly what Ian points out above as the argument in favor of explicit context passing. Basically, while I find it agreeable that structured concurrency is a good model, I'm unconvinced that it's the *only* model or the only model that should have access to Go's equivalent of ELV. As long as we want that, we have to pass context explicitly, ISTM. Note that the decision to tie ELV to structured concurrency is very intentional. The section "Problems with thread-local variables" mentions three problems with TLS: Unconstrained mutability, Unbounded lifetime and Expensive inheritance. Of these, the latter two are solved by tying the ELV to structured concurrency. In Go, they are solved by explicit passing of context.Context. There is one argument in that design doc in favor of ELV as a language environment construct in favor of the context.Context design: Performance. As ELV are supported implicitly by the compiler and runtime (that's the "Extent" in ELV), they can be much cheaper to access, as they don't need to walk the entire context stack. Instead (AIUI) the language environment provides a separate context.Context stack for each ELV. This is very similar to what I described a couple of years ago for local scoping in Go <https://blog.merovius.de/posts/2017-08-14-why-context-value-matters-and-how-to-improve-it/>. Another way we might try to address this in the future is by collapsing context.Context transparently (i.e. have each context.Context own a map[any]any and store the values in there). Again, I still don't see very strong arguments in favor of the Java ELV design over explicit passing. They explicitly decide not to allow the one thing that is argued in favor of argument passing - being able to inherit a context outside structured concurrency. I think that's a fine decision, I think restricting yourself to structured concurrency is a very defensible position to take - but I also don't think it's a decision Go necessarily has to follow. On Sat, Oct 1, 2022 at 8:47 AM Axel Wagner <axel.wagner...@googlemail.com> wrote: > On Sat, Oct 1, 2022 at 8:35 AM Robert Engels <reng...@ix.netcom.com> > wrote: > >> I read the structured concurrency paper and it indeed formalizes the >> ideas I derived from the original paper. If you review the examples it is >> implied that the context is supplied to workers via thread locals. The >> ideas presented in this paper define clearly what is lacking in the Go >> model - that the concurrency is unstructured and it leads to difficult to >> understand stack traces. >> > > This is an extreme stretch to me. Note that Java's concurrency is also > unstructured, with virtual threads as well. > > In both cases, the language and runtime provide concurrency primitives > which are then used and composed into higher level programming models. > The StructuredTaskScope is one way in which Java supports structured > concurrency on top of their unstructured concurrency model. errgroup.Group > and similar APIs are ways in which Go supports structured concurrency on > top of the unstructured concurrency model. There is no real contradiction > here. > > The one difference is that Java has TLS and Go doesn't. That's > unambiguously true, but there are reasons for that. Those reasons aren't > really addressed by anything I've read so far. And I think that's fine. I, > personally, wouldn't go so far as to say it's *bad* that Java has TLS, just > as little as I would say it's bad that Go doesn't have it. TLS has benefits > and it has downsides and it is entirely reasonable for two programming > languages to make different decisions about their inclusion. > > Note that TLS (or GLS) and similar primitives *are* periodically talked > about and I don't think it is categorically excluded to at least get > primitives which address *some* of the uses. sync.Pool is one such example. > However, Go tries to be careful about it and instead of adding general TLS, > which can be used for things it would consider good *and* bad, rather talks > about each individual use case built on top of it separately and tries to > forge them into APIs which allow for the good and prevent the bad. A > context.Context in TLS has so far been rejected because it seems the bad > outweighs the good. > > >> >> If a thread only exists to service a “request” it defacto represents the >> context so if you have the facility to carry context related state with the >> thread it eliminates the need to explicitly pass it as method parameters. >> >> On Oct 1, 2022, at 1:19 AM, Bakul Shah <ba...@iitbombay.org> wrote: >> >> Quoting from this article: "Virtual threads (JEP 425 >> <https://openjdk.org/jeps/425>) make it cost-effective to dedicate a >> thread to every such I/O operation, but managing the huge number of threads >> that can result remains a challenge." >> >> My quick take: may be this is due to "old thread think" as virtual >> threads are so new in Java? Has managing large number of goroutines been a >> problem? >> >> One use I can see for giving each thread a handle is for doing user level >> scheduling and in general treating them as first class objects. This may be >> a cost vs benefit issue. >> >> On Sep 30, 2022, at 10:49 PM, 'Axel Wagner' via golang-nuts < >> golang-nuts@googlegroups.com> wrote: >> >> Oh, following the link about Structured Concurrency at the end brings you >> to https://openjdk.org/jeps/428 >> That *does* indeed seem to contain discussion about relevant topics. >> Perhaps that's the link you intended to post? >> >> On Sat, Oct 1, 2022 at 7:45 AM Axel Wagner <axel.wagner...@googlemail.com> >> wrote: >> >>> I've at least skimmed the article and I can't find any of the arguments >>> you say are there. >>> For thread locals it says, if anything, that they should be avoided with >>> virtual threads - at least for some uses (the ones that you'd use a >>> sync.Pool for in Go). On coloring it only talks about the advantages of >>> virtual threads over async/await, which, well most Gophers will agree with. >>> >>> Apart from these, I can't find anything that I could reasonably connect >>> to context.Context - the article seems almost exclusively an introduction >>> to virtual threads and an explanation on how they differ from operating >>> system threads. In particular, I don't see anything in this article which >>> could address the arguments Ian mentioned. >>> >>> It teases at more articles, about "Structured Concurrency" and "Extent >>> local variables" - the latter sounds as if it *could* be what you talk >>> about, but that article doesn't seem to exist yet. >>> >>> On Sat, Oct 1, 2022 at 6:15 AM Robert Engels <reng...@ix.netcom.com> >>> wrote: >>> >>>> Again, please read the paper. The arguments you make are refuted. The >>>> lack of routine context is a burden on the Go ecosystem and makes debugging >>>> highly concurrent Go systems far more difficult than similar systems in >>>> Java. >>>> >>>> On Sep 30, 2022, at 11:09 PM, Rob Pike <r...@golang.org> wrote: >>>> >>>> >>>> One of the critical decisions in Go was not defining names for >>>> goroutines. If we give threads/goroutines/coroutines (TGCs) names or other >>>> identifiable state, such as contexts, there arises a tendency to push >>>> everything into one TGC. We see what this causes with the graphics thread >>>> in most modern graphics libraries, especially when using a >>>> threading-capable language such as Go. You are restricted in what you can >>>> do on that thread, or you need to do some sort of bottlenecking dance to >>>> have the full language available and still honoring the requirements of a >>>> single graphics thread. >>>> >>>> One way to see see what this means: Long ago, people talked of a >>>> "thread per request" model, and honestly it was, or would have been, an >>>> improvement on standard practice at the time. But if you have cheap TGCs, >>>> there is no need to stop there: You can use multiple independently >>>> executing TGCs to handle a request, or share a TGC between requests for >>>> some part of the work (think database access, for example). You have *the >>>> whole language available to you* when programming a request, including >>>> the ability to use TGCs. >>>> >>>> Like Ian, I have not read this paper, but I take it as a tenet that it >>>> is better to keep goroutines anonymous and state-free, and not to bind any >>>> particular calculation or data set to one thread of control *as part >>>> of the programming model*. If you want to do that, sure, go for it, >>>> but it's far too restrictive to demand it *a priori* and force it on >>>> others*.* >>>> >>>> -rob >>>> >>>> >>>> >>>> On Sat, Oct 1, 2022 at 1:39 PM Ian Lance Taylor <i...@golang.org> >>>> wrote: >>>> >>>>> On Fri, Sep 30, 2022 at 7:32 AM Robert Engels <reng...@ix.netcom.com> >>>>> wrote: >>>>> > >>>>> > Very interesting article came out recently. >>>>> https://www.infoq.com/articles/java-virtual-threads/ and it has >>>>> implications for the Go context discussion and the author makes a very >>>>> good >>>>> case as to why using the thread local to hold the context - rather than >>>>> coloring every method in the chain is a better approach. If the “virtual >>>>> thread aka Go routine” is extremely cheap to create you are far better off >>>>> creating one per request than pooling - in fact pooling becomes an anti >>>>> pattern. If you are creating one per request then the thread/routine >>>>> becomes the context that is required. No need for a distinct Context to be >>>>> passed to every method. >>>>> >>>>> I didn't read the article (sorry). >>>>> >>>>> In a network server a Go context is normally specific to, and shared >>>>> by, a group of goroutines acting on behalf of a single request. It is >>>>> also normal for a goroutine group to manage access to some resource, >>>>> in which case the context is passed in via a channel when invoking >>>>> some action on behalf of some request. Neither pattern is a natural >>>>> fit for a goroutine-local context. >>>>> >>>>> Ian >>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "golang-nuts" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to golang-nuts+unsubscr...@googlegroups.com. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/golang-nuts/CAOyqgcWAfdc2Np2KA%2B2-U9Z5Hv7tdHGgJHWDTUg_6pbr%3D8jghg%40mail.gmail.com >>>>> . >>>>> >>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "golang-nuts" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to golang-nuts+unsubscr...@googlegroups.com. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/golang-nuts/CAD38A60-EE4B-4A76-9F7B-66A9939874F5%40ix.netcom.com >>>> <https://groups.google.com/d/msgid/golang-nuts/CAD38A60-EE4B-4A76-9F7B-66A9939874F5%40ix.netcom.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/CAEkBMfEO-LVU_09itMwjdF-ciN_k9Dz_LthtWwgisMMz%2BQbMnw%40mail.gmail.com >> <https://groups.google.com/d/msgid/golang-nuts/CAEkBMfEO-LVU_09itMwjdF-ciN_k9Dz_LthtWwgisMMz%2BQbMnw%40mail.gmail.com?utm_medium=email&utm_source=footer> >> . >> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/DD955473-8C00-40BA-A11E-DE94BC01F80E%40iitbombay.org >> <https://groups.google.com/d/msgid/golang-nuts/DD955473-8C00-40BA-A11E-DE94BC01F80E%40iitbombay.org?utm_medium=email&utm_source=footer> >> . >> >> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEkBMfHjEi08RrFSC87YZUYBS1WSvq3VfBB1Tn5QxnTWD8oocg%40mail.gmail.com.