Where are channels and select? Why is async code special? Why do protocols have to be explicitly adopted? Why are errors "thrown" instead of returned?
Where are channels and select? Why is async code special? Why do protocols have to be explicitly adopted? Why are errors "thrown" instead of returned?
Normal languages just sort of call functions on threads - and use locks when there is contention. You certainly can write the same sort of code in Swift - but that is not how async functions work.
The issue with locks is that waiting on a lock could be expensive - depending on the type of lock. And it also ties up the thread. If you have a thread pool you could end up with a lot of threads getting tied up in locks.
Async functions are suspendible. When they encounter a data hazard - the thread is released and allowed to go work on something else. When the conflict clears the function is picked back up and execution continues. Note: the way this is designed means that a _different_ thread may continue execution of the async function, and async functions should assume that they may change threads during execution. But this does prevent stalled threads just waiting on some condition. The compiler needs to extra notation to know your function has been designed around this sort of operation.
Basically: Async functions are not normal functions - they're allowed to be suspendible and may change threads mid execution - hence the extra notation. This improves both performance and safety.
I’m am not well educated on the subject though so take that with a grain of salt.
For those curious I looked at Windows and Linux, but not much else.
Linux: no io_uring support. There's debate on even whether to use it as people are discussing security implications[2]. It looks like (from perusing this issue, but could be wrong) AIO wasn't used.
Windows: it looks like they're using IOCP everywhere. Seems sensible enough.
General case: there seems to be an open issue regarding this[3].
[1]: For example, Windows has IOCPs, Linux has io_uring, FreeBSD has kqueue, POSIX has... POSIX AIO, etc.
I was not aware that file I/O isn't async on Linux. Even so, I'm pretty sure network I/O and channel operations (send/receive/select) are async via epoll. I'm not as sure about these, but I think time.Sleep and sync.Mutex.Lock suspend the goroutine as well.