What is the difference between launch/join and async/await in Kotlin coroutines

前端 未结 8 2143
闹比i
闹比i 2020-11-30 17:17

In the kotlinx.coroutines library you can start new coroutine using either launch (with join) or async (with await<

8条回答
  •  不知归路
    2020-11-30 17:41

    launch and async are used to start new coroutines. But, they execute them in different manner.

    I would like to show very basic example which will help you understand difference very easily

    1. launch
        class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            btnCount.setOnClickListener {
                pgBar.visibility = View.VISIBLE
                CoroutineScope(Dispatchers.Main).launch {
                    val currentMillis = System.currentTimeMillis()
                    val retVal1 = downloadTask1()
                    val retVal2 = downloadTask2()
                    val retVal3 = downloadTask3()
                    Toast.makeText(applicationContext, "All tasks downloaded! ${retVal1}, ${retVal2}, ${retVal3} in ${(System.currentTimeMillis() - currentMillis)/1000} seconds", Toast.LENGTH_LONG).show();
                    pgBar.visibility = View.GONE
                }
            }
    
        // Task 1 will take 5 seconds to complete download
        private suspend fun downloadTask1() : String {
            kotlinx.coroutines.delay(5000);
            return "Complete";
        }
    
        // Task 1 will take 8 seconds to complete download    
        private suspend fun downloadTask2() : Int {
            kotlinx.coroutines.delay(8000);
            return 100;
        }
    
        // Task 1 will take 5 seconds to complete download
        private suspend fun downloadTask3() : Float {
            kotlinx.coroutines.delay(5000);
            return 4.0f;
        }
    }
    

    In this example, my code is downloading 3 data on click of btnCount button and showing pgBar progress bar until all download gets completed. There are 3 suspend functions downloadTask1(), downloadTask2() and downloadTask3() which downloads data. To simulate it, I've used delay() in these functions. These functions waits for 5 seconds, 8 seconds and 5 seconds respectively.

    As we've used launch for starting these suspend functions, launch will execute them sequentially (one-by-one). This means that, downloadTask2() would start after downloadTask1() gets completed and downloadTask3() would start only after downloadTask2() gets completed.

    As in output screenshot Toast, total execution time to complete all 3 downloads would lead to 5 seconds + 8 seconds + 5 seconds = 18 seconds with launch

    1. async

    As we saw that launch makes execution sequentially for all 3 tasks. The time to complete all tasks was 18 seconds.

    If those tasks are independent and if they do not need other task's computation result, we can make them run concurrently. They would start at same time and run concurrently in background. This can be done with async.

    async returns an instance of Deffered type, where T is type of data our suspend function returns. For example,

    • downloadTask1() would return Deferred as String is return type of function
    • downloadTask2() would return Deferred as Int is return type of function
    • downloadTask3() would return Deferred as Float is return type of function

    We can use the return object from async of type Deferred to get the returned value in T type. That can be done with await() call. Check below code for example

            btnCount.setOnClickListener {
            pgBar.visibility = View.VISIBLE
    
            CoroutineScope(Dispatchers.Main).launch {
                val currentMillis = System.currentTimeMillis()
                val retVal1 = async(Dispatchers.IO) { downloadTask1() }
                val retVal2 = async(Dispatchers.IO) { downloadTask2() }
                val retVal3 = async(Dispatchers.IO) { downloadTask3() }
    
                Toast.makeText(applicationContext, "All tasks downloaded! ${retVal1.await()}, ${retVal2.await()}, ${retVal3.await()} in ${(System.currentTimeMillis() - currentMillis)/1000} seconds", Toast.LENGTH_LONG).show();
                pgBar.visibility = View.GONE
            }
    

    This way, we've launched all 3 tasks concurrently. So, my total execution time to complete would be only 8 seconds which is time for downloadTask2() as it is largest of all of 3 tasks. You can see this in following screenshot in Toast message

提交回复
热议问题