Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin:withContext()vs Async await_Kotlin_Kotlin Coroutines - Fatal编程技术网

Kotlin:withContext()vs Async await

Kotlin:withContext()vs Async await,kotlin,kotlin-coroutines,Kotlin,Kotlin Coroutines,我一直在阅读,如果我理解正确,两个Kotlin函数的工作原理如下: withContext(context):切换当前协同路由的上下文,当给定块执行时,协同路由切换回上一个上下文 async(context):在给定的上下文中启动一个新的协程,如果我们对返回的Deferred任务调用.wait(),它将暂停调用协程,并在生成的协程内执行的块返回时恢复 下面是两个版本的code: 版本1: launch(){ block1() val returned = async(cont

我一直在阅读,如果我理解正确,两个Kotlin函数的工作原理如下:

  • withContext(context)
    :切换当前协同路由的上下文,当给定块执行时,协同路由切换回上一个上下文
  • async(context)
    :在给定的上下文中启动一个新的协程,如果我们对返回的
    Deferred
    任务调用
    .wait()
    ,它将暂停调用协程,并在生成的协程内执行的块返回时恢复
  • 下面是两个版本的
    code

    版本1:

      launch(){
        block1()
        val returned = async(context){
          block2()
        }.await()
        block3()
      }
    
      launch(){
        block1()
         val returned = withContext(context){
          block2()
        }
        block3()
      }
    
    版本2:

      launch(){
        block1()
        val returned = async(context){
          block2()
        }.await()
        block3()
      }
    
      launch(){
        block1()
         val returned = withContext(context){
          block2()
        }
        block3()
      }
    
  • 在这两个版本中,block1()和block3()都在默认上下文(commonpool?)中执行,其中as block2()在给定上下文中执行
  • 整体执行与block1()->block2()->block3()顺序同步
  • 我看到的唯一区别是版本1创建了另一个协同路由,其中as版本2在切换上下文时只执行一个协同路由
  • 我的问题是:

  • 使用
    与context
    而不是
    async wait
    是否总是更好,因为它在功能上类似,但不会创建另一个协同程序。大量的协同路由虽然轻量级,但在要求苛刻的应用程序中仍然可能是一个问题

  • 是否存在这样一种情况,即
    async wait
    with context
    更可取

  • 更新: 现在有一个代码检查,它可以将
    async(ctx){}.await()转换为withContext(ctx){}

    使用withContext不是总比使用AsynchAwait好,因为它在功能上类似,但不会创建另一个协同路由。大型numebrs协程,但在要求苛刻的应用程序中,轻量级可能仍然是一个问题

    是否存在AsynchWait比withContext更可取的情况

    要同时执行多个任务时,应使用async/await,例如:

    runBlocking {
        val deferredResults = arrayListOf<Deferred<String>>()
    
        deferredResults += async {
            delay(1, TimeUnit.SECONDS)
            "1"
        }
    
        deferredResults += async {
            delay(1, TimeUnit.SECONDS)
            "2"
        }
    
        deferredResults += async {
            delay(1, TimeUnit.SECONDS)
            "3"
        }
    
        //wait for all results (at this point tasks are running)
        val results = deferredResults.map { it.await() }
        println(results)
    }
    
    runBlocking{
    val delferredresults=arrayListOf()
    延迟结果+=异步{
    延迟(1,时间单位。秒)
    "1"
    }
    延迟结果+=异步{
    延迟(1,时间单位。秒)
    "2"
    }
    延迟结果+=异步{
    延迟(1,时间单位。秒)
    "3"
    }
    //等待所有结果(此时任务正在运行)
    val results=deferredResults.map{it.await()}
    println(结果)
    }
    
    如果不需要同时运行多个任务,可以使用withContext

    大量的协同路由虽然轻量级,但在要求苛刻的应用程序中仍然是一个问题

    我想通过量化实际成本来消除“太多的合作项目”是一个问题的神话

    首先,我们应该将协同程序本身从它所连接的协同程序上下文中分离出来。这就是如何以最小的开销创建协同程序:

    GlobalScope.launch(Dispatchers.Unconfined) {
        suspendCoroutine<Unit> {
            continuations.add(it)
        }
    }
    
    这段代码启动一系列协同程序,然后休眠,这样您就有时间使用VisualVM之类的监视工具分析堆。我创建了专门的类
    JobList
    ContinuationList
    ,因为这样更容易分析堆转储


    为了获得更完整的故事,我还使用下面的代码来衡量
    withContext()
    async await
    的成本:

    import kotlinx.coroutines.*
    import java.util.concurrent.Executors
    import kotlin.coroutines.suspendCoroutine
    import kotlin.system.measureTimeMillis
    
    const val JOBS_PER_BATCH = 100_000
    
    var blackHoleCount = 0
    val threadPool = Executors.newSingleThreadExecutor()!!
    val ThreadPool = threadPool.asCoroutineDispatcher()
    
    fun main(args: Array<String>) {
        try {
            measure("just launch", justLaunch)
            measure("launch and withContext", launchAndWithContext)
            measure("launch and async", launchAndAsync)
            println("Black hole value: $blackHoleCount")
        } finally {
            threadPool.shutdown()
        }
    }
    
    fun measure(name: String, block: (Int) -> Job) {
        print("Measuring $name, warmup ")
        (1..1_000_000).forEach { block(it).cancel() }
        println("done.")
        System.gc()
        System.gc()
        val tookOnAverage = (1..20).map { _ ->
            System.gc()
            System.gc()
            var jobs: List<Job> = emptyList()
            measureTimeMillis {
                jobs = (1..JOBS_PER_BATCH).map(block)
            }.also { _ ->
                blackHoleCount += jobs.onEach { it.cancel() }.count()
            }
        }.average()
        println("$name took ${tookOnAverage * 1_000_000 / JOBS_PER_BATCH} nanoseconds")
    }
    
    fun measureMemory(name:String, block: (Int) -> Job) {
        println(name)
        val jobs = (1..JOBS_PER_BATCH).map(block)
        (1..500).forEach {
            Thread.sleep(1000)
            println(it)
        }
        println(jobs.onEach { it.cancel() }.filter { it.isActive})
    }
    
    val justLaunch: (i: Int) -> Job = {
        GlobalScope.launch(Dispatchers.Unconfined) {
            suspendCoroutine<Unit> {}
        }
    }
    
    val launchAndWithContext: (i: Int) -> Job = {
        GlobalScope.launch(Dispatchers.Unconfined) {
            withContext(ThreadPool) {
                suspendCoroutine<Unit> {}
            }
        }
    }
    
    val launchAndAsync: (i: Int) -> Job = {
        GlobalScope.launch(Dispatchers.Unconfined) {
            async(ThreadPool) {
                suspendCoroutine<Unit> {}
            }.await()
        }
    }
    
    是的,
    async wait
    的时间大约是
    withContext
    的两倍,但仍然只有一微秒。你必须在一个紧密的循环中启动它们,除此之外几乎什么都不做,这样才能在你的应用程序中成为一个“问题”

    使用
    measureMemory()
    我发现每次调用的内存开销如下:

    Just launch: 88 bytes
    withContext(): 512 bytes
    async-await: 652 bytes
    
    async await
    的成本比
    withContext
    高出140字节,后者是我们得到的一个协程的内存重量。这只是设置
    CommonPool
    上下文的全部成本的一小部分

    如果性能/内存影响是决定
    withContext
    async await
    之间的唯一标准,那么得出的结论是,在99%的实际用例中,它们之间没有相关差异

    真正的原因是
    withContext()
    是一种更简单、更直接的API,特别是在异常处理方面:

    • async{…}
      中未处理的异常会导致其父作业被取消。无论您如何处理匹配的
      await()
      中的异常,都会发生这种情况。如果您没有为它准备
      coroutineScope
      ,它可能会导致整个应用程序宕机
    • withContext{…}
      中未处理的异常只会被
      withContext
      调用抛出,您可以像处理其他异常一样处理它
    withContext
    也恰巧得到了优化,利用了暂停父协同路由并等待子协同路由的事实,但这只是一个额外的好处

    async await
    应该为那些您实际需要并发的情况保留,这样您就可以在后台启动多个协同路由,然后才等待它们。简言之:

    • async await async await
      -不要这样做,使用
      withContext with context
    • async-async-await-await
      -这就是使用它的方法

      • 当有疑问时,请记住这一点,就像经验法则一样:

      • 如果多个任务必须并行执行,并且最终结果取决于所有任务的完成,则使用
        async

      • 要返回单个任务的结果,请使用
        withContext


      • 我认为,当您将
        与上下文一起使用时,总是会创建一个新的协同程序。这是我从源代码中看到的。@stdout不
        async/await
        还创建了一个新的协同程序,根据OP?关于
        的额外内存开销