1

Chris Lattner wrote in his Swift Concurrency Manifesto that:

It is typically "not ok" to block the current thread of execution just because something is taking a while to load.

Similarly, Roman Elizarov wrote in his Blocking threads, suspending coroutines article that:

Threads are expensive, so blocking a thread is something that should be avoided.

Does this sentiment extend to background threads1 in the context of Android and iOS applications? If so, what are some disadvantages of blocking a background thread in the context of an Android or iOS application?

1 By "background thread", I mean a thread which is not the main/UI thread.

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147

2 Answers2

2

Blocking the main thread is normally not ok because the OS uses that thread for various things, and if that thread is blocked it can't use it. For example, on Android the main thread is used for message processing, so if the main thread can't return to the looper then it can't process messages. That would cause it to not draw, because drawing is a message.

Blocking a background thread is ok, but not maximally efficient in a language/framework with coroutines like kotlin. Coroutines basically allow multiple tasks to share a thread and swap between them when one of them suspends. So if you're writing in kotlin, it's preferable to use coroutines for IO bound tasks. There is still a place for Threads (especially for CPU bound tasks and high performance tasks like game updates), but most things like network calls, db access, etc are more efficient using coroutines on a shared thread pool.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
2

Roughly speaking, both of these quotes are abstract arguments for asynchronous programming patterns, but neither was intended as a categorical prohibition against ever blocking any thread.

Perhaps it goes without saying, but on both platforms, we never block the main thread. It leads to an unresponsive or stuttering UI. (And if it happens at the wrong time on iOS, at least, might result in your app being summarily terminated for non-responsiveness.) On both platforms, the relevant asynchronous patterns are designed largely to avoid blocking the main thread.

But, regarding background threads, we would still favor asynchronous API over synchronous ones:

  1. Asynchronous API frequently offer greater flexibility. For example, asynchronous API often offer the capability to cancel operations that are underway, something that synchronous API rarely support.

  2. In iOS, the number of available background threads is surprisingly limited. If you block too many threads in “thread explosion” scenarios (e.g., more than 64 threads), you can exhaust the GCD worker thread pool and can even lead to deadlocks. If you use asynchronous API, control the degree of concurrency, and avoid blocking threads, this problem can be avoided.

  3. In iOS, Swift concurrency is “cooperative” and is predicated on a contract to always ensure forward progress. If you block an actor, the cooperative thread pool can be exhausted even more quickly, leading to deadlocks and other performance issues. See this answer.

  4. FWIW, the caveat about “threads are expensive” is true, but in iOS, the thread pools (the GCD “worker thread pool” or Swift concurrency’s “cooperative thread pool”) abstract us away of the cost of spinning up new threads. So the computational expense of threads is not generally the operative concern. Other factors (e.g., those outlined above) usually are the more pressing concern.

So, in short, avoid blocking even a background thread where possible. And where you must block threads, make sure to mitigate against the degenerate scenarios.

Rob
  • 415,655
  • 72
  • 787
  • 1,044