Kotlin coroutine - the difference between Launch and Async

If you want to call a coroutine in a non-suspend method, you need to use launch or async.

Launch and async comparison

Same point:

  1. Both launch and async builders can be used to execute tasks asynchronously.
    Both of them can start a new coroutine in the coroutine context, and the execution of the coroutine is asynchronous and will not block the current thread.
  2. The join() method of launch and the await() method of async will block the current coroutine body, but will not block the current thread.
  3. Deferred inherits from the Job interface, and it has everything that Job has, adding a method await, which receives the value returned in the async closure

The only difference: the return value is different

  • The job of launch carries the return value, and the Deferred of async carries the return value

runBlocking

launch and async will not block the current thread, but runBlocking will block the current thread

First, we define a suspend function for demonstration

//域名解析是一个耗时操作,故用协程实现
private suspend fun analysisDns() = suspendCancellableCoroutine<String> {
    
    
    thread {
    
    
        try {
    
    
            val ipAddress = InetAddress.getByName("www.baidu.com")
            showLog(2, ipAddress.hostAddress)
            it.resume(ipAddress.hostAddress)
        } catch (e: Exception) {
    
    
            it.resume("解析失败: $e")
        }
    }
}


//输出日志,以及当前线程
fun showLog(i: Int, msg: String = "") {
    
    
    println("$i --- ${
      
      Thread.currentThread().name}   $msg")
}

//防止程序过早结束,看不到效果
private fun end() {
    
    
    print("\n----------------------------- 输入任意键结束 -----------------------------\n\n")
    readLine()
}

1、Launch

definition

val testLaunch: () -> Unit = {
    
    
    showLog(0)
    GlobalScope.launch {
    
    
        showLog(1)
        analysisDns()
        showLog(3)
    }
    showLog(4)
}

use

fun main() {
    
    
    testLaunch.invoke()
    end()
}

log output

0 --- main   
4 --- main   

----------------------------- 输入任意键结束 -----------------------------

1 --- DefaultDispatcher-worker-2   
2 --- Thread-2   14.119.104.189
3 --- DefaultDispatcher-worker-2   


Process finished with exit code 0
  • launch executes asynchronously, no need to return results, and will not block the current thread
  • 0, 4 current thread, will not be blocked
  • If the end() function is not used, only 0 will be output, and the program will end after 4.

2、Launch Join()

definition

val testLaunchJoin: () -> Unit = {
    
    
    showLog(-1)

    GlobalScope.launch {
    
    
        showLog(0)
        val job = GlobalScope.launch {
    
    
            showLog(1)
            analysisDns()
            showLog(3)
        }
        showLog(4)
        job.join()
        showLog(5)
    }

    showLog(6)
}

use

fun main() {
    
    
    testLaunchJoin.invoke()
    end()
}

log output

-1 --- main   
6 --- main   

----------------------------- 输入任意键结束 -----------------------------

0 --- DefaultDispatcher-worker-1   
4 --- DefaultDispatcher-worker-1   
1 --- DefaultDispatcher-worker-2   
2 --- Thread-2   14.119.104.189
3 --- DefaultDispatcher-worker-1   
5 --- DefaultDispatcher-worker-1   


Process finished with exit code 0
  • The join() method of launch can only be called within the body of the coroutine
  • join() will block the current coroutine body, not the current thread
  • -1, 6 is the current thread and will not be blocked
  • 0, 4, 5 are the coroutines where the join is located and will be blocked

3、Async

definition

val testAsync: () -> Unit = {
    
    
    showLog(0)
    GlobalScope.async {
    
    
        showLog(1)
        analysisDns()
        showLog(3)
    }
    showLog(4)
}

use

fun main() {
    
    
    testAsync.invoke()
    end()
}

log output

0 --- main   
4 --- main   

----------------------------- 输入任意键结束 -----------------------------

1 --- DefaultDispatcher-worker-1   
2 --- Thread-2   14.119.104.254
3 --- DefaultDispatcher-worker-1   


Process finished with exit code 0
  • async executes asynchronously, the last line of lambda returns the result without blocking the current thread
  • 0, 4 current thread, will not be blocked

4、Async Await()

definition

val testAsyncAwait: () -> Unit = {
    
    
    showLog(-1)

    GlobalScope.launch {
    
    
        showLog(0)
        val deferred = GlobalScope.async {
    
    
            showLog(1)
            analysisDns()
            showLog(3)
            "Deferred返回值"
        }
        showLog(4)
        val res = deferred.await()
        showLog(5, res)
    }

    showLog(6)
}

use

fun main() {
    
    
    testAsyncAwait.invoke()
    end()
}

log output

-1 --- main   
6 --- main   

----------------------------- 输入任意键结束 -----------------------------

0 --- DefaultDispatcher-worker-2   
4 --- DefaultDispatcher-worker-2   
1 --- DefaultDispatcher-worker-1   
2 --- Thread-2   14.119.104.254
3 --- DefaultDispatcher-worker-2   
5 --- DefaultDispatcher-worker-2   Deferred返回值


Process finished with exit code 0
  • The await() method of async can only be called in the coroutine body
  • await() will block the current coroutine body, not the current thread
  • -1, 6 is the current thread and will not be blocked
  • 0, 4, 5 are the coroutines where the join is located and will be blocked

5、Runblocking

definition

val testRunBlocking: () -> Unit = {
    
    
    showLog(0)

    runBlocking {
    
    
        showLog(1)
        analysisDns()
        showLog(3)
    }

    showLog(4)
}

use

fun main() {
    
    
    testRunBlocking.invoke()
}

log output

0 --- main   
1 --- main   
2 --- Thread-0   14.119.104.189
3 --- main   
4 --- main   

Process finished with exit code 0
  • The coroutine task started by runBlocking will block the current thread until the coroutine execution ends

Guess you like

Origin blog.csdn.net/weixin_41733225/article/details/130473923