← Back to context

Comment by hinkley

4 hours ago

We use async code in two modes which have different very different consequences for concurrency issues.

We have an imperative code flow where we perform a series of tasks that involve IO, and apply the effects sequentially. Here the biggest problem is holding a lock for a long transaction and starving the rest of the system. So we break it up into a finite state machine where the lock is held mostly during the synchronous parts.

The other is asking a lot of questions and then making a decision based on the sum of the answers. These actually happen in parallel, and we often have to relax the effective isolation levels to make this work. But it always seems to work better if the parallel task can be treated as a pure function. Purity removes side effects, which removes the need for write locks, which if applied consistently removes the Dining Philosopher’s problem. “Applied consistently” is the hard part. Because it requires not just personal discipline but team and organizational discipline.

> There is usually not much of a point in writing a finalizer that touches only the object being finalized, since such object updates wouldn’t normally be observable. Thus useful finalizers must touch global shared state.

That seems like an “Abandon hope, all ye who enter here.”

There's a reason Java got rid of finalizers. It forces the programmer to choose between synchronous cleanup (`AutoCloaseable`) or asynchronous cleanup on a thread (`Cleaner`).