Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Goroutines and Async-Await are two very different takes on the same problem. In that regard, preferring Go over C# is an incredibly good reason to keep using it instead of switching over to C#. Choice is good, I prefer more languages than fewer.


I know essentially nothing about go - could you explain simply what goroutines are?


I'm far from being an expert at Go, but I will try: goroutines are green threads (very light threads, if you prefer). The main difference between async calls and threads is that threads remove the distinction between synchronous and asynchronous code.

In C# or Python 3, each function is colored as either sync or async. You can quite easily call an async function from a sync context, but doing a blocking sync call from an async context is forbidden (although possible).

In Go there is no such distinction: you just write your functions in a straightforward fashion, as if everything was synchronous, and then wrap whatever you want to run in the background in a goroutine. If you don't need the return value from that function, it is has simple as issuing:

  go my_func(param_a, param_b, ...)
Note that goroutines are green threads, not OS threads, so you can easily spawn many tens of thousands of them without bringing your system to a halt.


It is worth noting that the key to this is that the language is designed so that even the synchronous appearing APIs for things like file IO actually use the non-blocking system calls under the hood, so that the OS thread does not get blocked, and other goroutines can be scheduled.

When calling into C code, there is additional overhead of potentially creating a new OS thread to continue running goroutines on, since go has absolutely no idea if the C code will block, but since the average C library does use blocking IO, it needs to either assume the worse, or alternative have an OS thread dedicated to monitoring for kernel level blocking, and spawning new goroutinine runing threads. (I believe the assume C calls may block approach is used.) It has heuristics to avoid creating a new OS thread every time, but in any case, if you have many goroutines calling a blocking C function call, it means you have many blocked OS threads too.


Async is to deal with io not for all concurrency in general. It uses interupts, not threads. Although the implementation can use threads for optimisation, it is not the point. If you're waiting on a network socket or reading lots of files, you don't need to spawn a new thread for each item. You can instead schedule a task to run one an interupt is received.


You are entirely correct. My sentence "The main difference between async calls and threads is that threads remove the distinction between synchronous and asynchronous code." is pretty weird: I wasn't talking about threads in general, but green threads as used by Go (i.e. Goroutines) in particular.

The idea that I wanted to express is that, very broadly, there are two ways of dealing with concurrent io. One is to deal with it explicitly at call site, using some variation of async/await semantic, futures, promises, or just callbacks. That's the C#/Python 3.4+/javascript way of doing it. Although implementations vary wildly between these languages, the core idea remains the same.

The other way of dealing with concurrent io is using green threads (or related concepts like actors) as in Go, Elixir, Python with gevent, etc. IO calls don't look special (no await, no yield, no special keyword, no callback), that is to say they behave like any other function call (although the implementation of these io calls is non-blocking to allow other green threads to run). Concurrent io from the programmer perspective is achieved simply by spawning many green threads/actors.

I personally find green threads easier to reason about than async calls, especially in the long run when maintaining large software.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: