laterJob

fun laterJob(name: String? = null, job: () -> Unit)

Run the provided callback within a job pool running within libnexakotlin. This job pool is serviced by between 4 and 25 threads.

Job pools verses coroutines: Coroutines are a great way to run a quick function asynchronously.

However, it is not recommended to launch thread blocking or long running tasks in coroutines since that coroutine will consume a handling thread. This will eventually result in arbitrary coroutines not executing. One solution is to allocate a lot of runner threads but these threads are allocated statically, so waste resources, and clutter up debugging analysis. The JobPool allocates a minimum number of threads, and then dynamically grows them if needed. Ultimately if a limit is hit, a callback can be installed to indicate that the threads are exhausted (probably lots of jobs are stuck). At that point, you can drop into the debugger and analyze the stuck jobs.

Coroutines also virally spread the "suspend" keyword. If a coroutine calls another blocking function, the subfunction really needs to be marked as suspend and to be rewritten to not block (only use coroutine-style blocks). This can take a lot of effort and ultimately result in having 2 versions of the same functions.

Due to the architecture of coroutines, it is very difficult to debug them if you need to discover 2 things:

  1. Where is this coroutine and why isn't it running? (you can't look for them on a queue)

  2. Why is this coroutine stuck and where was it called from? (coroutines don't preserve the call stack)

However, threads arguably use more resources since context switching from one thread to another is CPU expensive. So ultimately it is a tradeoff to use a "Job" verses a coroutine.