协程

2018-12-06  本文已影响2人  主音King

协程使用场景
高负荷网络IO、文件IO、CPU/GPU密集型任务

协程是轻量级线程
启动100,000个协程,每秒打印一个点。全部在[main,5,main]中耗时4.5s左右打印完成。内存波动比较小(占内存小)
启动相同个数的线程(大多数情况下会内存溢出错误),在Thread[Thread-2-->Thread-100001,5,main]即使全部打印完成需要2.3min左右。内存波动比较大(占内存大)
如果换做

fun main() = runBlocking {
    repeat(100_000) { // 启动大量的协程
        launch {
            delay(1000L)
            print(".")
        }
    }
}

GlobalScope.launch { …… } 替换 thread { …… }
delay(……) 替换 Thread.sleep(……)
delay是特别的挂起函数,不会造成线程阻塞,挂起函数只能在协程中使用
Thread.sleep()是阻塞等待
GlobalScope.launch{}大括号中所在线程:Thread[DefaultDispatcher-worker-1,5,main]。属于非主线程

        GlobalScope.launch { // 在后台启动一个新的协程并继续
            delay(1000L) // 无阻塞的等待1秒钟(默认时间单位是毫秒)
            println("测试-World!-${Thread.currentThread()} ${Looper.getMainLooper() == Looper.myLooper()}") // 在延迟后打印输出
        }
        println("测试-Hello,") // 主线程的协程将会继续等待
        Thread.sleep(2000L) // 阻塞主线程2秒钟来保证 JVM 存活

桥接阻塞和非阻塞
runBlocking:显式的阻塞
runBlocking{}线程名:Thread[main,5,main]属于住线程

        GlobalScope.launch {
            // 在后台启动一个新的协程并继续
            delay(1000L) // 无阻塞的等待1秒钟(默认时间单位是毫秒)
            println("测试-World!-${Thread.currentThread()} ${Looper.getMainLooper() == Looper.myLooper()}") // 在延迟后打印输出
        }
        println("测试-Hello,") // 主线程的协程将会继续等待
        runBlocking { // 阻塞……我们延迟2秒来保证 JVM 的存活
            delay(2000L)
        }

惯用方法

   fun main() = runBlocking<Unit> {
       GlobalScope.launch {
           delay(1000L)
           println("${TAG}-${Thread.currentThread()}-world!")
       }
       println("${TAG}-${Thread.currentThread()}-hello,")
       delay(2000L)
   }

等待一个任务

    fun main() = runBlocking<Unit> {
        val job = GlobalScope.launch { // 启动一个新的协程并保持对这个任务的引用
            delay(1000L)
            println("${TAG}-${Thread.currentThread()}-world")
        }
        println("${TAG}-${Thread.currentThread()}-hello,")
        job.join() // 等待直到子协程执行结束
    }

结构化并发
由GlobalScope.launch改为launch
这里两次打印所在的线程:Thread[main,5,main]都在主线程中
猜测:这个结构化并发是阻塞的
验证的确是阻塞的:launch竟然在主线程中,尝试了下在launch中的delay延迟8s,在activity的onCreate或者onResume中调用。竟然阻塞了ui(actionBar、TextView中的内容竟然8s后才显示)

    fun main() = runBlocking {
        launch {
            // 启动一个新的协程并保持对这个任务的引用
            delay(1000L)
            println("${TAG}-${Thread.currentThread()}-world")
        }
        println("${TAG}-${Thread.currentThread()}-hello,")
    }

作用域构建器

fun main() = runBlocking { // this: CoroutineScope
    // main@coroutine#1
    launch { 
        // main @coroutine#2
        delay(200L)
        println("${Thread.currentThread()}-Task from runBlocking")
    }
  
    coroutineScope { // 创建一个新的协程作用域
        // main @coroutine#1
        launch {
            // main @coroutine#3
            delay(500L) 
            println("${Thread.currentThread()}-Task from nested launch")
        }
        
        delay(100L)
        println("${Thread.currentThread()}-Task from coroutine scope") // 该行将在嵌套启动之前执行打印
    }
    // main@coroutine#1
    println("${Thread.currentThread()}-Coroutine scope is over") // 该行将在嵌套结束之后才会被打印
}

提取函数重构
suspend:修饰会被暂停的函数,只能用着协程或其他suspend函数当中

fun main() = runBlocking {
    launch { doWorld() }
    println("${Thread.currentThread()}-Hello,")
}

// 你的第一个挂起函数
suspend fun doWorld() {
    delay(1000L)
    println("${Thread.currentThread()}-World!")
}

像守护线程一样的全局协程
如下代码:会输出三次:0、1、2

GlobalScope.launch {
    repeat(1000) { i ->
            println("I'm sleeping $i ...")
        delay(500L)
    }
}
delay(1300L) // 在延迟之后结束程序
上一篇 下一篇

猜你喜欢

热点阅读