代码之家  ›  专栏  ›  技术社区  ›  Roman Elizarov

Kotlin协同路由中的启动/加入和异步/等待有什么区别

  •  242
  • Roman Elizarov  · 技术社区  · 7 年前

    kotlinx.coroutines 库,您可以使用 launch (带 join )或 async await

    8 回复  |  直到 6 年前
        1
  •  337
  •   YektaDev    3 年前
    • launch 习惯于 开火忘记协同程序 发射 异常终止,然后将其视为 未捕获 join 用于等待启动的协同路由完成,并且不会传播其异常。然而,一辆汽车坠毁了 小孩

    • async 习惯于 启动计算某些结果的协同程序 . 结果由的实例表示 Deferred 必须 使用 await 异步 代码存储在生成的 推迟 并且不会在其他任何地方交付,除非经过处理,否则会自动删除。 您一定不要忘记使用async启动的协同程序 .

        2
  •  117
  •   YektaDev    3 年前

    我发现 this guide

    从本质上讲,协程是轻量级线程。

    因此,您可以将协程视为以非常有效的方式管理线程的东西。

    ¤ 发射

    fun main(args: Array<String>) {
        launch { // launch new coroutine in background and continue
            delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
            println("World!") // print after delay
        }
        println("Hello,") // main thread continues while coroutine is delayed
        Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
    }
    

    所以 launch Job join 关于这个 发射

    fun main(args: Array<String>) = runBlocking<Unit> {
        val job = launch { // launch new coroutine and keep a reference to its Job
            delay(1000L)
            println("World!")
        }
        println("Hello,")
        job.join() // wait until child coroutine completes
    }
    

    异步

    在概念上, async 发射 . 它启动一个单独的协程,这是一个与所有其他协程并行工作的轻量级线程。不同之处在于,launch返回一个 并且不携带任何结果值,而async返回 Deferred

    所以 异步 启动后台线程,执行某些操作,并立即返回令牌,如下所示: .

    fun main(args: Array<String>) = runBlocking<Unit> {
        val time = measureTimeMillis {
            val one = async { doSomethingUsefulOne() }
            val two = async { doSomethingUsefulTwo() }
            println("The answer is ${one.await() + two.await()}")
        }
        println("Completed in $time ms")
    }
    

    您可以使用 .await() 以获得最终结果,但 推迟 也是一个 工作

    推迟 实际上是一个 工作 Read this

    interface Deferred<out T> : Job (source)
    

    有一个惰性选项可以使用值为的可选启动参数进行异步 CoroutineStart.LAZY await 或者如果调用了启动函数。

        3
  •  17
  •   Kushal    5 年前

    launch async 用于启动新的协同程序。但是,他们以不同的方式执行它们。

    我想展示一个非常基本的例子,它将帮助你们非常容易地理解差异

    1. 发射
        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;
        }
    }
    

    在本例中,我的代码是点击下载3个数据 btnCount 按钮和显示 pgBar 进度条,直到所有下载完成。有3个 suspend 功能 downloadTask1() downloadTask2() downloadTask3() 下载数据。为了模拟它,我使用了 delay() 在这些函数中。这些函数等待 5 seconds 8 seconds 5秒

    发射 为了启动这些暂停功能, 顺序(一个接一个) . 这意味着, downloadTask2() downloadTask1() downloadTask3() downloadTask2() 已完成。

    Toast ,完成所有3次下载的总执行时间将导致 5秒+8秒+5秒=18秒 具有

    Launch Example

    发射 执行 sequentially 18 seconds .

    concurrently . 它们将同时启动,并在后台并发运行。这可以用 .

    异步 Deffered<T> 类型,其中 T 是挂起函数返回的数据类型。例如

    • 将返回 Deferred<String>
    • 将返回 Deferred<Int>
    • 将返回 Deferred<Float>

    异步 Deferred<T> 类型这可以用 await() 呼叫检查以下代码示例

            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
            }
    

    这样,我们同时启动了所有3个任务。所以,我要完成的总执行时间只有 这是时间 downloadTask2() Toast message

    await example

        4
  •  15
  •   AouledIssa    5 年前
    1. 这两个协同路由生成器(即启动和异步)基本上都是lambda,接收器类型为CoroutineScope,这意味着它们的内部块被编译为挂起函数,因此它们都以异步模式运行,并且都将按顺序执行其块。

    2. 协同程序生成器(启动和异步)都是可取消的。

    3. 还有什么吗yep with launch如果在其块内引发异常,则会自动取消协同路由并交付异常。另一方面,如果异步发生这种情况,则异常不会进一步传播,应该在返回的延迟对象中捕获/处理。

    4. https://kotlinlang.org/docs/tutorials/coroutines/coroutines-basic-jvm.html https://www.codementor.io/blog/kotlin-coroutines-6n53p8cbn1

        5
  •  8
  •   Himanshu Yadav    4 年前

    Async和Launch都用于创建在后台运行的协同路由。几乎在任何情况下,都可以使用其中任何一种。

    当您不关心任务的返回值,只想运行它时,可以使用Launch。如果需要任务/协同例程的返回类型,则应使用async。

    候补 : 然而,我觉得上述差异/方法是从Java/每个请求一个线程模型的角度考虑的结果。协同路由非常便宜,如果您想从某个任务/协同路由(比如说服务调用)的返回值中做一些事情,最好从该返回值中创建一个新的协同路由。如果您希望一个协程等待另一个协程来传输一些数据,我建议使用通道,而不是延迟对象的返回值。使用通道并根据需要创建尽可能多的协同路由是更好的方法

    详细答案 :

    唯一的区别在于返回类型和它提供的功能。

    发布回报 Job 而异步返回 Deferred . 有趣的是,延迟延长了工作时间。这意味着它必须在作业的基础上提供额外的功能。Deferred是参数化的类型,其中T是返回类型。因此,延迟对象可以从异步方法执行的代码块返回一些响应。

        6
  •  5
  •   Dr.jacky Mateusz Kaflowski    3 年前

    发射

    异步 返回结果(延迟作业)

    launch join 用于等待作业完成。它只是暂停协同例程调用 join() ,同时让当前线程自由地执行其他工作(如执行另一个协程)。

    async Deferred . 当结果延迟被取消时,正在运行的协同路由被取消。

    考虑一个返回字符串值的异步方法。如果使用异步方法时没有 await 它将返回一个 推迟 字符串,但如果 等候


    两者之间的关键区别 异步 发射

        7
  •  2
  •   Dr.jacky Mateusz Kaflowski    3 年前

    enter image description here

    • 在不需要结果时使用,
    • 不要在调用的地方阻塞代码,
    • 按顺序运行

    结果异步

    • 当您需要等待结果时,可以并行运行
    • 在调用的位置阻止代码,
    • 并发运行
        8
  •  0
  •   JaviCasa    4 年前

    除了其他很棒的答案外,对于熟悉Rx和参与协作的人来说, async Deferred 这类似于 Single 虽然 launch 返回a Job 这更类似于 Completable .await() .join() 阻止,直到 已完成。