juliocbcotta
06/13/2022, 7:06 AMrunBLocking
, but I everybody says we shouldn't be using that, so what should I be using?Joffrey
06/13/2022, 7:23 AMrunBlocking
? It is correct to use it when the API calling you expects to block the thread until the result is ready. So in a callback from a library like this, this is totally fine, especially because OkHttp likely uses its own thread pool, and exposes blocking APIs itselfjuliocbcotta
06/13/2022, 7:27 AMyschimke
06/13/2022, 7:51 AMyschimke
06/13/2022, 7:52 AMyschimke
06/13/2022, 7:52 AMJoffrey
06/13/2022, 7:53 AMintercept()
). Because OkHttp needs your result when the method returns, and doesn't provide a way to give the result asynchronously, there is nothing you can do but block that thread until the result is ready. You just need to be aware that coroutines launched inside that runBlocking
won't be able to use that blocked thread, which should be fine because it should be part of OkHttp's own thread poolyschimke
06/13/2022, 7:57 AMjuliocbcotta
06/13/2022, 8:01 AMyschimke
06/13/2022, 8:03 AMJoffrey
06/13/2022, 8:12 AMsuspend
and provides no async way like a Future
or Deferred
or callback to return that result).
In that case, the contract of that function is to block the calling thread until the result is ready. There is no way around that, you can dispatch what you want on any thread, the calling thread will still have to be blocked while waiting for the result - it's how that API was designed. In that sense, that's what runBlocking
is for, it even uses that blocked thread to do the work, which is nice.
Now, if that function is called on the main thread by the library, then that means you have to block the main thread to do whatever you have to do there. This also probably means you shouldn't be doing long work like network calls or DB access in there at all, the problem is not really runBlocking
here, it's the semantics of what you're trying to call. If you're in this situation, there is no magic coroutine construct that will help you, you'll have to work around the design of the library on a case-by-case basis.juliocbcotta
06/13/2022, 8:17 AMrunBlocking
from the main thread, you can't switch dispatchers inside the called suspended function or it will cause a dead lock in the main thread as in the issue I pointed a few comments above.juliocbcotta
06/13/2022, 8:17 AMNick Allen
06/13/2022, 8:29 AMTL;DR: Don't block the main thread with runBlocking. It produces all sorts of weird stuff.
juliocbcotta
06/13/2022, 8:31 AMrunBlocking
is not an option, what do I have as option then?
• Not using coroutines?Joffrey
06/13/2022, 8:31 AMrunBlocking
does if you don't switch context), but at the moment coroutines don't allow you to go back and forth 2 levels deep runBlocking { withContext(IO) { withContext(Main) { ... }}}
.
This is something that could technically be solved by coroutines, I'm still not 100% sure it should be, but it could. That might lead to weird ordering of code execution maybe? Don't know.juliocbcotta
06/13/2022, 8:34 AMrunBlocking { withContext(IO) { }}
breaks the main thread.Joffrey
06/13/2022, 9:03 AMthe contract of that function is to block the calling thread until the result is ready. There is no way around that, you can dispatch what you want on any thread, the calling thread will still have to be blocked while waiting for the result - it's how that API was designed
juliocbcotta
06/13/2022, 9:05 AMuli
06/13/2022, 12:36 PMuli
06/13/2022, 12:37 PMuli
06/13/2022, 12:38 PMuli
06/13/2022, 12:41 PMJoffrey
06/13/2022, 1:11 PM.immediate
AFAIU. But if you schedule it with withContext(Dispatchers.Main)
it does hang immediately (not at the end of the block)Joffrey
06/13/2022, 1:14 PMrunBlocking
manages to reuse the current thread as an event-loop, and yet fails to use this event loop when using withContext(Main)
like this. It makes sense though, because going through the main dispatcher is not the same as the runBlocking
event loop itself, but still it's surprising