3 ms·
The async question is actually really interesting - and gets at a few things Swift does very differently from some other languages. Normal languages just sort
by illusionyodel 2y ago
The async question is actually really interesting - and gets at a few things Swift does very differently from some other languages.
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.
- kbolino 2y agoBut that's the thing, we're comparing with Go, where all functions behave that way, and no async/await ceremony is required. Go has many weaknesses, but I don't think a language that treats async as unusual/special beats Go in that respect.
- developerDan 2y agoThis is just a hunch but likely because of the application the two languages were originally designed for. Go is/was a purely backend lang (as I understand it) whereas Swift was built with the UI in mind which must be run on the main thread. So Swift has async/await for making clear boundaries between synchronous (aka UI) operations and asynchronous operations. I’m am not well educated on the subject though so take that with a grain of salt.
- kbolino 2y agoThis is a good point. It's possible to use Go this way too, but it gets tricky. You can lock the main goroutine to its O/S thread with runtime.LockOSThread and then do the heavy lifting on other goroutines, sending messages back to the main goroutine typically using channels. Given Swift's lineage, this is probably more ergonomic there than in Go.
- jkrejcha 2y agoThis melding of the sync and the async is actually kinda interesting to me. I know that at least in lots of environments, the sync and async paths are effectively separate for things like I/O[1]. I wondered (and still do for some cases) how Go handles this. 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. [2]: https://github.com/golang/go/issues/31908 https://github.com/golang/go/issues/31908 [3]: https://github.com/golang/go/issues/6817 https://github.com/golang/go/issues/6817
- kbolino 2y agoInteresting. My understanding of how things get implemented is that all code runs essentially "async" by default, but the runtime scheduler can switch to running code synchronously when requested (runtime.LockOSThread) or necessary (e.g. "slow" calls to C via cgo). 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.