-1

When we start OS level threads, we will create a stack for each thread, and this has some cost. It is discussed here: Threads vs. Async that using coroutines, async and await can reduce this cost.

So, how does a program store local variables in an async function, so that when we come back to the function, we can recover all the variables, without using another stack? How is this implemented?

Maybe I should ask a more specific question, how does this work in Golang/javascript? These are places where coroutines are known to be efficient. They might use multithreading, but not all coroutine are threads.

esqew
  • 42,425
  • 27
  • 92
  • 132
Mr User
  • 205
  • 1
  • 5
  • In JavaScript it's the basic mechanism that supports the idea of closures, and in particular generator functions. – Pointy May 18 '23 at 19:22
  • To the person who closes this as duplicate: the word "coroutine" never appears anywhere in the question you link. How can you close something without reading the title! – Mr User May 18 '23 at 19:35
  • 1
    The term "coroutine" has nothing to do with it really; it's based on closures. – Pointy May 18 '23 at 19:36
  • Also the title does not include the word "coroutine". – Pointy May 18 '23 at 19:38
  • 1
    Also also, a single question about two very different programming languages does not make a lot of sense. – Pointy May 18 '23 at 19:40
  • @Pointy Closures can be used without coroutines. It is complete separate. Even if coroutines needs closures, it needs LOTS of explanations. – Mr User May 18 '23 at 19:43
  • @Pointy I am asking a generic question, and just giving examples I can think of in languages. – Mr User May 18 '23 at 19:44
  • I have to side with @MrUser here. I believe this to be a valid and indeed well-stated question. Frankly the fact that this was closed within 10 minutes of it being asked is shameful. I do not understand higher-ranking users' obsessions with shutting down valid questions. Adding on to that, the fact that this question has **absolutely nothing** to do with the question mentioned to be a duplicate is ridiculous – J-Cake May 18 '23 at 19:47
  • "how" it's implemented is entirely an implementation detail with no relationship between javascript and Go. In Go a goroutione is started with a function call, and that function call stores the scope like any other function call, being a goroutine makes no difference from the caller's perspective. – JimB May 18 '23 at 20:33
  • @JimB How can go store the state of local variables then - a function call will terminate very soon - the coroutine on the other hand might last very long. – Mr User May 18 '23 at 20:37
  • @MrUser, I don't understand what you are trying to ask. It doesn't matter how long the function takes to return, the function scope is the function scope. – JimB May 18 '23 at 20:39
  • @JimB What do you mean by "In Go a goroutione is started with a function call"? – Mr User May 18 '23 at 20:55
  • @MrUser, from a users perspective a goroutine doesn't _do_ anything besides execute a function. Whether it's the argument to `go` or `main` itself, the goroutine runs until the function returns. – JimB May 18 '23 at 20:59
  • @JimB I am asking about implementation and low level stuff. – Mr User May 18 '23 at 21:21
  • Then you need to look at the individual implementation you are interested in. The linked duplicates cover the general concept which is about as good as we can do for such a non-specific question. – JimB May 18 '23 at 21:35
  • @JimB The question IS very specific. If you think a question must "look at the individual implementation" to be specific, then you are not understanding the meaning of the English word "specific". That's not what it means. – Mr User May 18 '23 at 22:18

1 Answers1

-1

I'm not able to answer the question for the Go side of things, as I don't really dabble there myself, but the JavaScript side is hopefully a little easier, and you can potentially draw analogues to Go from there.

In JavaScript (depending on implementation), you are strictly limited to one thread, meaning a single stack. As all threads share heap space, and most JS implementations heap-allocate just about everything, and only keep references on their stack, all threads can access the data at the same time, regardless of where they're accessed from.

Async functions actually have very little to do with this. Specifically, async functions are just regular functions which inform the engine to get back to this later. They also access the same variables.

This is where Garbage Collection comes in. GC allows the source code to define variables, and have it reference-counted. When you call an async function, the variables are declared, meaning their reference counts are 0. It's important to note, that the variables are declared at the invocation of the function, not at the invocation of the program, meaning each call of the function allocates its memory afresh - you keep a new heap-allocated value for each call. This is essentially a closure. All functions define closures as they create a stack frame and all variables used within the closure have some defined way to access their value.

The reference-counting mechanism ensures that you have access to this data as long as you need it, and that you can ensure that despite the same variable name, you're actually referring to different memory.

To summarise, async functions don't do any magic in terms of managing memory, they just hold their own. In principle, this is exactly the same as calling a synchronous function, only that it runs out-of-order.

I presume Go does something very similar. In terms of multithreading across async functions, depending on whether you use a heap-allocated value, the same principle applies unless you explicitly share the memory, which Go advises against.

J-Cake
  • 1,526
  • 1
  • 15
  • 35
  • This is not correct. JavaScript `async` functions are based on the generator mechanism. An `await` in an `async` function is like a `yield` in a generator. – Pointy May 18 '23 at 19:37
  • 2
    That's correct, but how does this influence my answer? – J-Cake May 18 '23 at 19:41
  • What exactly does "they just hold their own" even mean? – Pointy May 18 '23 at 19:42
  • It means that functions, async or not, to the observer behave like closures. The variables defined within them are visible only within the closure. – J-Cake May 18 '23 at 19:42
  • @J-Cake So we need to copy data from the heap each time we come back to the function, or do we just use the same heap variable each time, and all local variables are on heap? – Mr User May 18 '23 at 20:06
  • I think copying isn't quite right. The data lives in the namespace of the program itself, you you can just access it as usual. The difference is that new data gets allocated each time you call the function – J-Cake May 19 '23 at 21:13