Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run two jobs in parallel but wait for another job to finish using kotlin coroutines

I have these jobs below:

  1. Inflating a complex calendar view async
  2. Downloading events A
  3. Downloading events B
  4. Adding calendar view to it's parent
  5. Adding A events to the calendar
  6. Adding B events to the calendar

I want

  • 1, 2, 3 have to start async,
  • 4 has to wait for 1
  • 5 has to wait for 2 and 4
  • 6 has to wait for 3 and 4
  • 6 and 5 should not be dependent to each other, can run at different times.
  • 4 is only dependent to 1, so it can run before 2 or 3 is finished.

I've tried async await but it makes them finish at the same time (as expected). I think this example might be a good way to learn parallel programming concepts, like semaphores mutex or spin locks. But it's too complicated for me to understand.

How should I implement these with using Kotlin coroutines?

like image 384
osrl Avatar asked Dec 25 '18 10:12

osrl


People also ask

How do you wait for a function to finish in Kotlin?

To wait for a coroutine to finish, you can call Job. join . join is a suspending function, meaning that the coroutine calling it will be suspended until it is told to resume. At the point of suspension, the executing thread is released to any other available coroutines (that are sharing that thread or thread pool).

Do Kotlin coroutines run in parallel?

Android Online Course for Professionals by MindOrks Similarly, we can do any type of background tasks in parallel using Kotlin Coroutines.

Can coroutines in Kotlin be suspended and resumed mid execution?

Coroutines can suspend themselves, and the dispatcher is responsible for resuming them. To specify where the coroutines should run, Kotlin provides three dispatchers that you can use: Dispatchers. Main - Use this dispatcher to run a coroutine on the main Android thread.

How do you use await in Kotlin?

In order to migrate to the async/await pattern, you have to return the async() result from your code, and call await() on the Deferred , from within another coroutine. By doing so, you can remove callbacks you used to use, to consume asynchronously provided values.


1 Answers

It's pretty straightforward. All you need to do is:

  1. Implement CoroutineScope and create CoroutineContext, or use GlobalScope.
  2. Using local CoroutineScope or GlobalScope.launch() launch the coroutine.
  3. In the coroutine use async/await to run/wait asynchronous operations.

You can apply next code to your algorithm (all explanations are in the comments):

class SomeClass : CoroutineScope {
    private var job: Job = Job()

    // creating local CoroutineContext
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job

    // cancel the Job if it is no longer needed
    fun onClear() {
        job.cancel()
    }

    fun doJob() {
        // launch coroutine
        launch {
            // run Job1, Job2, Job3 in parallel, asyncIO - is an extension function on CoroutineScope
            val d1 = asyncIO { job1() }
            val d2 = asyncIO { job2() }
            val d3 = asyncIO { job3() }

            // waiting for result of Job1
            val job1Result = d1.await()

            // run Job4
            val d4 = asyncIO { job4(job1Result) }

            // waiting for result of Job2 and Job4
            val job2Result = d2.await()
            val job4Result = d4.await()

            // run Job5
            val d5 = asyncIO { job5(job2Result, job4Result) }

            // waiting for result of Job3
            val job3Result = d3.await()

            // run Job6
            val d6 = asyncIO { job6(job3Result, job4Result) }

            onDone(d5.await(), d6.await())
        }
    }

    private fun onDone(job5Result: String, job6Result: String) {
        // do something with result of Job5 and Job6
    }


    fun job1(): String {
        return "Result of job1"
    }

    fun job2(): String {
        return "Result of job2"
    }

    fun job3(): String {
        return "Result of job3"
    }

    fun job4(job1Result: String): String {
        return "Result of job4"
    }

    fun job5(job2Result: String, job4Result: String): String {
        return "Result of job5"
    }

    fun job6(job3Result: String, job4Result: String): String {
        return "Result of job6"
    }

    // extension function
    fun <T> CoroutineScope.asyncIO(ioFun: () -> T) = async(Dispatchers.IO) { ioFun() }
}
like image 104
Sergey Avatar answered Oct 15 '22 17:10

Sergey