Hacker News new | ask | show | jobs
by KingOfCoders 1658 days ago
I only have rudimentary knowledge of Golang (but think the blocked/green automatic scheduling is excellent).

How does go nest aync calls?

func f() { }

func g() { }

func h() { go g() go f() }

What happens on

f()

Are the g() and f() calls inside h() blocking? Or are they async and the block happens at the point of return? Which would be the main difference to languages with an async keyword, were you need to be explicit about blocking.

1 comments

The go keyword executes the called function asynchronously so g() and f() won't block h(). If you need a computed result from g() or f() then you'll need to use a channel or a shared mutex guarded value to get it. A channel is the correct default choice and the mutex should only be used if you need it for performance or other reasons.
I understood from the OP that in Golang the sync and async code would be the same - contrary to e.g. Rust were you have async/wait. Go achieves this with coroutines and the go keyword.

f()

is a sync call to the function f, and the function f used async calls inside. Somewhere then needs to be a transition from async to sync contexts (aka wait/block).

I wondered where this happens.

From your comment I assume there is a difference, in sync code I would do

x = f()

while in async code I would use

f(channel)

?

Close. If I execute say want to run some function asynchronously I use the go keyword to execute it. But I can't get a return value if I do that so I need some other mechanism to get the return value. One way is to pass a channel into the function and expect the function to return the value to me via that channel. like so:

    func f(ch chan[int]) {
     ch <- 1 // depending on the channel implementation this is a blocking action
    }
then I can call that function asynchronously

    go f(ch)
and later when I want the value from f I can retrieve it from the channel

    i := <-ch // this is a blocking call
The net effect of the all the above is that async and non async code is highly composable. if I have a function that computes a value and I want to get that value asynchronously then I can wrap it in a function that uses a channel to get the value to me.

    go func() { ch<-f() }
Every function is a potential asynchronous function.
"The net effect of the all the above is that async and non async code is highly composable."

How does this differ from Rust (Or Typescript etc.) where we would use

  async f() -> i32 { }

  fn g() { f().wait() }
to block?
Thanks a lot! Can only upvote you once sadly.