Kotlin协程 - Launch和Async的区别

如果想要在一个非挂起(suspend)方法中调用协程,则需要使用launch或async方式。

launch和async对比

相同点:

  1. launch 和 async 构建器都可以用于异步执行任务。
    它们都可以在协程上下文中启动一个新的协程,并且该协程的执行是异步的,不会阻塞当前线程。
  2. launch的join()方法、async的await()方法会阻塞当前协程体, 但不会阻塞当前线程。
  3. Deferred 继承自 Job 接口,Job有的它都有,增加了一个方法 await ,这个方法接收的是 async 闭包中返回的值

唯一不同点:返回值不同

  • launch的Job携带返回值,async的Deferred携带返回值

runBlocking

launch和async不会阻塞当前线程,但runBlocking会阻塞当前线程

首先,我们定义一个挂起函数用于演示

//域名解析是一个耗时操作,故用协程实现
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

定义

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

使用

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

日志输出

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 异步执行,无需返回结果,不会阻塞当前线程
  • 0, 4当前线程, 不会被阻塞
  • 若不使用end()函数,则只会输出0,4后程序便结束。

2、Launch Join()

定义

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)
}

使用

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

日志输出

-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
  • launch的join()方法,要在协程体内才可调用
  • join()会阻塞当前协程体, 不会阻塞当前线程
  • -1, 6是当前线程 ,不会被阻塞
  • 0, 4, 5是join所在协程, 会被阻塞

3、Async

定义

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

使用

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

日志输出

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 异步执行,lambda最后一行为返回结果,不会阻塞当前线程
  • 0, 4当前线程, 不会被阻塞

4、Async Await()

定义

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)
}

使用

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

日志输出

-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
  • async的await()方法,要在协程体内才可调用
  • await()会阻塞当前协程体, 不会阻塞当前线程
  • -1, 6是当前线程 ,不会被阻塞
  • 0, 4, 5是join所在协程, 会被阻塞

5、Runblocking

定义

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

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

    showLog(4)
}

使用

fun main() {
    
    
    testRunBlocking.invoke()
}

日志输出

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

Process finished with exit code 0
  • runBlocking启动的协程任务会 阻断当前线程,直到该协程执行结

猜你喜欢

转载自blog.csdn.net/weixin_41733225/article/details/130473923