📝Is blocking I/O worth coloring?

tags

Function color

What Color is Your Function? argues that having threads is enough to avoid function coloring.

True, you can technically avoid coloring if threads can block on I/O. However, blocking system calls have quite a few caveats around them, so that you might want to avoid them in certain cases and they are worth calling out / distinguishing from other functions.

Parking the whole OS thread in syscall is also more costly, which is the main reason why some languages that already have threads still implement async-await (e.g., Rust, C#, Kotlin).

Counterarguments

  • How blocking syscalls are different from CPU-heavy functions? Both may “block” the thread for quite a bit.
    • CPU-heavy functions are usually more predictable.
  • Blocking I/O may also happen at other places besides syscalls. For example, page miss may trigger reading swapped out page from disk.
  • In case of Go, I/O functions don’t have color even though they block the current goroutine. Haskell is similar, although all potentially blocking functions live under IO monad.

Answer

Coloring creates a strong distinction and allows specifying where I/O or waiting is acceptable. In many cases, this is not important and dynamism/flexibility is preferred.

However, when performance matters, knowing when the code may block is important. In these cases, it’s worth calling out and explicitly allowing/forbidding arbitrary I/O at certain sections. And that’s where § Effect systems can be helpful.

Await/blocking points are also important when language is reliant on cooperative concurrency, as these points are the ones where application state may change (Cooperative concurrency makes it hard to have colorless asynchrony).

Backlinks