Kotlin协程Dispatchers原理示例详解

目录
  • 前置知识
    • demo
    • startCoroutineCancellable
    • intercepted()函数
    • DefaultScheduler中找dispatch函数
    • Runnable传入
    • Worker线程执行逻辑
  • 小结

前置知识

Kotlin协程不是什么空中阁楼,Kotlin源代码会被编译成class字节码文件,最终会运行到虚拟机中。所以从本质上讲,Kotlin和Java是类似的,都是可以编译产生class的语言,但最终还是会受到虚拟机的限制,它们的代码最终会在虚拟机上的某个线程上被执行。

之前我们分析了launch的原理,但当时我们没有去分析协程创建出来后是如何与线程产生关联的,怎么被分发到具体的线程上执行的,本篇文章就带大家分析一下。

要想搞懂Dispatchers,我们先来看一下Dispatchers、CoroutineDispatcher、ContinuationInterceptor、CoroutineContext之间的关系

public actual object Dispatchers {
    @JvmStatic
    public actual val Default: CoroutineDispatcher = DefaultScheduler
    @JvmStatic
    public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher
    @JvmStatic
    public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.Unconfined
    @JvmStatic
    public val IO: CoroutineDispatcher = DefaultIoScheduler
}
public abstract class CoroutineDispatcher :
    AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
}
public interface ContinuationInterceptor : CoroutineContext.Element {}
public interface Element : CoroutineContext {}

Dispatchers中存放的是协程调度器(它本身是一个单例),有我们平时常用的IO、Default、Main等。这些协程调度器都是CoroutineDispatcher的子类,这些协程调度器其实都是CoroutineContext。

demo

我们先来看一个关于launch的demo:

fun main() {
    val coroutineScope = CoroutineScope(Job())
    coroutineScope.launch {
        println("Thread : ${Thread.currentThread().name}")
    }
    Thread.sleep(5000L)
}

在生成CoroutineScope时,demo中没有传入相关的协程调度器,也就是Dispatchers。那这个launch会运行到哪个线程之上?

运行试一下:

Thread : DefaultDispatcher-worker-1

居然运行到了DefaultDispatcher-worker-1线程上,这看起来明显是Dispatchers.Default协程调度器里面的线程。我明明没传Dispatchers相关的context,居然会运行到子线程上。说明运行到default线程是launch默认的。

它是怎么与default线程产生关联的?打开源码一探究竟:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    //代码1
    val newContext = newCoroutineContext(context)
    //代码2
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    //代码3
    coroutine.start(start, coroutine, block)
    return coroutine
}
  • 将传入的CoroutineContext构造出新的context
  • 启动模式,判断是否为懒加载,如果是懒加载则构建懒加载协程对象,否则就是标准的
  • 启动协程

我们重点关注代码1,这是与CoroutineContext相关的。

public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {
    //从父协程那里继承过来的context+这次的context
    val combined = coroutineContext.foldCopiesForChildCoroutine() + context
    val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined
    //combined可以简单的把它看成是一个map,它是CoroutineContext类型的
    //如果当前context不等于Dispatchers.Default,而且从map里面取ContinuationInterceptor(用于拦截之后分发线程的)值为空,说明没有传入协程应该在哪个线程上运行的相关参数
    return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null)
        debug + Dispatchers.Default else debug
}

调用launch的时候,我们没有传入context,默认参数是EmptyCoroutineContext。这里的combined,它其实是CoroutineContext类型的,可以简单的看成是map(其实不是,只是类似)。

通过combined[ContinuationInterceptor]可以将传入的线程调度相关的参数给取出来,这里如果取出来为空,是给该context添加了一个Dispatchers.Default,然后把新的context返回出去了。所以launch默认情况下,会走到default线程去执行。

补充一点:CoroutineContext能够通过+连接是因为它内部有个public operator fun plus函数。能够通过combined[ContinuationInterceptor]这种方式访问元素是因为有个public operator fun get函数。

public interface CoroutineContext {
     /**
     * Returns the element with the given [key] from this context or `null`.
     */
    public operator fun <E : Element> get(key: Key<E>): E?
     /**
     * Returns a context containing elements from this context and elements from  other [context].
     * The elements from this context with the same key as in the other one are dropped.
     */
    public operator fun plus(context: CoroutineContext): CoroutineContext {
        ......
    }
}

startCoroutineCancellable

上面我们分析了launch默认情况下,context中会增加Dispatchers.Default的这个协程调度器,到时launch的Lambda会在default线程上执行,其中具体流程是怎么样的,我们分析一下。

在之前的文章 Kotlin协程之launch原理 中我们分析过,launch默认情况下会最终执行到startCoroutineCancellable函数。

public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) {
    //构建ContinuationImpl
    createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit))
}
public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
    completion: Continuation<T>
): Continuation<Unit> {
    val probeCompletion = probeCoroutineCreated(completion)
    return if (this is BaseContinuationImpl)
        //走这里
        create(probeCompletion)
    else
        createCoroutineFromSuspendFunction(probeCompletion) {
            (this as Function1<Continuation<T>, Any?>).invoke(it)
        }
}

在Kotlin协程之launch原理 文章中,咱们分析过create(probeCompletion)这里创建出来的是launch的那个Lambda,编译器会产生一个匿名内部类,它继承自SuspendLambda,而SuspendLambda是继承自ContinuationImpl。

所以 createCoroutineUnintercepted(completion)一开始构建出来的是一个ContinuationImpl,接下来需要去看它的intercepted()函数。

intercepted()函数

internal abstract class ContinuationImpl(
    completion: Continuation<Any?>?,
    private val _context: CoroutineContext?
) : BaseContinuationImpl(completion) {
    constructor(completion: Continuation<Any?>?) : this(completion, completion?.context)
    public override val context: CoroutineContext
        get() = _context!!
    @Transient
    private var intercepted: Continuation<Any?>? = null
    public fun intercepted(): Continuation<Any?> =
        intercepted
            ?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
                .also { intercepted = it }
}

第一次走到intercepted()函数时,intercepted肯定是为null的,还没初始化。此时会通过context[ContinuationInterceptor]取出Dispatcher对象,然后调用该Dispatcher对象的interceptContinuation()函数。这个Dispatcher对象在demo这里其实就是Dispatchers.Default。

public actual object Dispatchers {
    @JvmStatic
    public actual val Default: CoroutineDispatcher = DefaultScheduler
}

可以看到,Dispatchers.Default是一个CoroutineDispatcher对象,interceptContinuation()函数就在CoroutineDispatcher中。

public abstract class CoroutineDispatcher :
    AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
    public final override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
        DispatchedContinuation(this, continuation)
}
public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) {
    createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit))
}

这个方法非常简单,就是新建并且返回了一个DispatchedContinuation对象,将this和continuation给传入进去。这里的this是Dispatchers.Default。

所以,最终我们发现走完startCoroutineCancellable的前2步之后,也就是走完intercepted()之后,创建的是DispatchedContinuation对象,最后是调用的DispatchedContinuation的resumeCancellableWith函数。最后这步比较关键,这是真正将协程的具体执行逻辑放到线程上执行的部分。

internal class DispatchedContinuation<in T>(
    //这里传入的dispatcher在demo中是Dispatchers.Default
    @JvmField val dispatcher: CoroutineDispatcher,
    @JvmField val continuation: Continuation<T>
) : DispatchedTask<T>(MODE_UNINITIALIZED), CoroutineStackFrame, Continuation<T> by continuation {
    inline fun resumeCancellableWith(
        result: Result<T>,
        noinline onCancellation: ((cause: Throwable) -> Unit)?
    ) {
        val state = result.toState(onCancellation)
        //代码1
        if (dispatcher.isDispatchNeeded(context)) {
            _state = state
            resumeMode = MODE_CANCELLABLE
            //代码2
            dispatcher.dispatch(context, this)
        } else {
            //代码3
            executeUnconfined(state, MODE_CANCELLABLE) {
                if (!resumeCancelled(state)) {
                    resumeUndispatchedWith(result)
                }
            }
        }
    }
}
internal abstract class DispatchedTask<in T>(
    @JvmField public var resumeMode: Int
) : SchedulerTask() {
    ......
}
internal actual typealias SchedulerTask = Task
internal abstract class Task(
    @JvmField var submissionTime: Long,
    @JvmField var taskContext: TaskContext
) : Runnable {
    ......
}
public abstract class CoroutineDispatcher :
    AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
    public abstract fun dispatch(context: CoroutineContext, block: Runnable)
    public open fun isDispatchNeeded(context: CoroutineContext): Boolean = true
}

从DispatchedContinuation的继承结构来看,它既是一个Continuation(通过委托给传入的continuation参数),也是一个Runnable。

  • 首先看代码1:这个dispatcher在demo中其实是Dispatchers.Default ,然后调用它的isDispatchNeeded(),这个函数定义在CoroutineDispatcher中,默认就是返回true,只有Dispatchers.Unconfined返回false
  • 代码2:调用Dispatchers.Default的dispatch函数,将context和自己(DispatchedContinuation,也就是Runnable)传过去了
  • 代码3:对应Dispatchers.Unconfined的情况,它的isDispatchNeeded()返回false

现在我们要分析代码2之后的执行逻辑,也就是将context和Runnable传入到dispatch函数之后是怎么执行的。按道理,看到Runnable,那可能这个与线程执行相关,应该离我们想要的答案不远了。回到Dispatchers,我们发现Dispatchers.Default是DefaultScheduler类型的,那我们就去DefaultScheduler中或者其父类中去找dispatch函数。

DefaultScheduler中找dispatch函数

public actual object Dispatchers {
    @JvmStatic
    public actual val Default: CoroutineDispatcher = DefaultScheduler
}
internal object DefaultScheduler : SchedulerCoroutineDispatcher(
    CORE_POOL_SIZE, MAX_POOL_SIZE,
    IDLE_WORKER_KEEP_ALIVE_NS, DEFAULT_SCHEDULER_NAME
) {
    ......
}
internal open class SchedulerCoroutineDispatcher(
    private val corePoolSize: Int = CORE_POOL_SIZE,
    private val maxPoolSize: Int = MAX_POOL_SIZE,
    private val idleWorkerKeepAliveNs: Long = IDLE_WORKER_KEEP_ALIVE_NS,
    private val schedulerName: String = "CoroutineScheduler",
) : ExecutorCoroutineDispatcher() {
    private var coroutineScheduler = createScheduler()
    private fun createScheduler() =
        CoroutineScheduler(corePoolSize, maxPoolSize, idleWorkerKeepAliveNs, schedulerName)
     override fun dispatch(context: CoroutineContext, block: Runnable): Unit = coroutineScheduler.dispatch(block)
}

最后发现dispatch函数在其父类SchedulerCoroutineDispatcher中,在这里构建了一个CoroutineScheduler,直接调用了CoroutineScheduler对象的dispatch,然后将Runnable(也就是上面的DispatchedContinuation对象)传入。

Runnable传入

internal class CoroutineScheduler(
    @JvmField val corePoolSize: Int,
    @JvmField val maxPoolSize: Int,
    @JvmField val idleWorkerKeepAliveNs: Long = IDLE_WORKER_KEEP_ALIVE_NS,
    @JvmField val schedulerName: String = DEFAULT_SCHEDULER_NAME
) : Executor, Closeable {
    override fun execute(command: Runnable) = dispatch(command)
    fun dispatch(block: Runnable, taskContext: TaskContext = NonBlockingContext, tailDispatch: Boolean = false) {
        trackTask() // this is needed for virtual time support
        //代码1:构建Task,Task实现了Runnable接口
        val task = createTask(block, taskContext)
        //代码2:取当前线程转为Worker对象,Worker是一个继承自Thread的类
        val currentWorker = currentWorker()
        //代码3:尝试将Task提交到本地队列并根据结果执行相应的操作
        val notAdded = currentWorker.submitToLocalQueue(task, tailDispatch)
        if (notAdded != null) {
            //代码4:notAdded不为null,则再将notAdded(Task)添加到全局队列中
            if (!addToGlobalQueue(notAdded)) {
                throw RejectedExecutionException("$schedulerName was terminated")
            }
        }
        val skipUnpark = tailDispatch && currentWorker != null
        // Checking 'task' instead of 'notAdded' is completely okay
        if (task.mode == TASK_NON_BLOCKING) {
            if (skipUnpark) return
            //代码5: 创建Worker并开始执行该线程
            signalCpuWork()
        } else {
            // Increment blocking tasks anyway
            signalBlockingWork(skipUnpark = skipUnpark)
        }
    }
    private fun currentWorker(): Worker? = (Thread.currentThread() as? Worker)?.takeIf { it.scheduler == this }
    internal inner class Worker private constructor() : Thread() {
        .....
    }
}

观察发现,原来CoroutineScheduler类实现了java.util.concurrent.Executor接口,同时实现了它的execute方法,这个方法也会调用dispatch()。

  • 代码1:首先是通过Runnable构建了一个Task,这个Task其实也是实现了Runnable接口,只是把传入的Runnable包装了一下
  • 代码2:将当前线程取出来转换成Worker,当然第一次时,这个转换不会成功,这个Worker是继承自Thread的一个类
  • 代码3:将task提交到本地队列中,这个本地队列待会儿会在Worker这个线程执行时取出Task,并执行Task
  • 代码4:如果task提交到本地队列的过程中没有成功,那么会添加到全局队列中,待会儿也会被Worker取出来Task并执行
  • 代码5:创建Worker线程,并开始执行

开始执行Worker线程之后,我们需要看一下这个线程的run方法执行的是啥,也就是它的具体执行逻辑。

Worker线程执行逻辑

internal inner class Worker private constructor() : Thread() {
    override fun run() = runWorker()
    private fun runWorker() {
        var rescanned = false
        while (!isTerminated && state != WorkerState.TERMINATED) {
            //代码1
            val task = findTask(mayHaveLocalTasks)
            if (task != null) {
                rescanned = false
                minDelayUntilStealableTaskNs = 0L
                //代码2
                executeTask(task)
                continue
            } else {
                mayHaveLocalTasks = false
            }
            if (minDelayUntilStealableTaskNs != 0L) {
                if (!rescanned) {
                    rescanned = true
                } else {
                    rescanned = false
                    tryReleaseCpu(WorkerState.PARKING)
                    interrupted()
                    LockSupport.parkNanos(minDelayUntilStealableTaskNs)
                    minDelayUntilStealableTaskNs = 0L
                }
                continue
            }
            tryPark()
        }
        tryReleaseCpu(WorkerState.TERMINATED)
    }
    fun findTask(scanLocalQueue: Boolean): Task? {
        if (tryAcquireCpuPermit()) return findAnyTask(scanLocalQueue)
        // If we can't acquire a CPU permit -- attempt to find blocking task
        val task = if (scanLocalQueue) {
            localQueue.poll() ?: globalBlockingQueue.removeFirstOrNull()
        } else {
            globalBlockingQueue.removeFirstOrNull()
        }
        return task ?: trySteal(blockingOnly = true)
    }
    private fun executeTask(task: Task) {
        val taskMode = task.mode
        idleReset(taskMode)
        beforeTask(taskMode)
        runSafely(task)
        afterTask(taskMode)
    }
    fun runSafely(task: Task) {
        try {
            task.run()
        } catch (e: Throwable) {
            val thread = Thread.currentThread()
            thread.uncaughtExceptionHandler.uncaughtException(thread, e)
        } finally {
            unTrackTask()
        }
    }
}

run方法直接调用的runWorker(),在里面是一个while循环,不断从队列中取Task来执行。

  • 代码1:从本地队列或者全局队列中取出Task
  • 代码2:执行这个task,最终其实就是调用这个Runnable的run方法。

也就是说,在Worker这个线程中,执行了这个Runnable的run方法。还记得这个Runnable是谁么?它就是上面我们看过的DispatchedContinuation,这里的run方法执行的就是协程任务,那这块具体的run方法的实现逻辑,我们应该到DispatchedContinuation中去找。

internal class DispatchedContinuation<in T>(
    @JvmField val dispatcher: CoroutineDispatcher,
    @JvmField val continuation: Continuation<T>
) : DispatchedTask<T>(MODE_UNINITIALIZED), CoroutineStackFrame, Continuation<T> by continuation {
    ......
}
internal abstract class DispatchedTask<in T>(
    @JvmField public var resumeMode: Int
) : SchedulerTask() {
    public final override fun run() {
        assert { resumeMode != MODE_UNINITIALIZED } // should have been set before dispatching
        val taskContext = this.taskContext
        var fatalException: Throwable? = null
        try {
            val delegate = delegate as DispatchedContinuation<T>
            val continuation = delegate.continuation
            withContinuationContext(continuation, delegate.countOrElement) {
                val context = continuation.context
                val state = takeState() // NOTE: Must take state in any case, even if cancelled
                val exception = getExceptionalResult(state)
                /*
                 * Check whether continuation was originally resumed with an exception.
                 * If so, it dominates cancellation, otherwise the original exception
                 * will be silently lost.
                 */
                val job = if (exception == null && resumeMode.isCancellableMode) context[Job] else null
                //非空,且未处于active状态
                if (job != null && !job.isActive) {
                    //开始之前,协程已经被取消,将具体的Exception传出去
                    val cause = job.getCancellationException()
                    cancelCompletedResult(state, cause)
                    continuation.resumeWithStackTrace(cause)
                } else {
                    //有异常,传递异常
                    if (exception != null) {
                        continuation.resumeWithException(exception)
                    } else {
                        //代码1
                        continuation.resume(getSuccessfulResult(state))
                    }
                }
            }
        } catch (e: Throwable) {
            // This instead of runCatching to have nicer stacktrace and debug experience
            fatalException = e
        } finally {
            val result = runCatching { taskContext.afterTask() }
            handleFatalException(fatalException, result.exceptionOrNull())
        }
    }
}

我们主要看一下代码1处,调用了resume开启协程。前面没有异常,才开始启动协程,这里才是真正的开始启动协程,开始执行launch传入的Lambda表达式。这个时候,协程的逻辑是在Worker这个线程上执行的了,切到某个线程上执行的逻辑已经完成了。

ps: rusume会走到BaseContinuationImpl的rusumeWith,然后走到launch传入的Lambda匿名内部类的invokeSuspend方法,开始执行状态机逻辑。前面的文章 Kotlin协程createCoroutine和startCoroutine原理 我们分析过这里,这里就只是简单提一下。

到这里,Dispatchers的执行流程就算完了,前后都串起来了。

小结

Dispatchers是协程框架中与线程交互的关键。底层会有不同的线程池,Dispatchers.Default、IO,协程任务来了的时候会封装成一个个的Runnable,丢到线程中执行,这些Runnable的run方法中执行的其实就是continuation.resume,也就是launch的Lambda生成的SuspendLambda匿名内部类,也就是开启协程状态机,开始协程的真正执行。

以上就是Kotlin协程Dispatchers原理示例详解的详细内容,更多关于Kotlin协程Dispatchers的资料请关注我们其它相关文章!

(0)

相关推荐

  • Kotlin实现Android系统悬浮窗详解

    目录 Android 弹窗浅谈 系统悬浮窗具体实现 权限申请 代码设计 具体实现 FloatWindowService 类 FloatWindowManager 类 FloatWindowManager 类代码 FloatLayout 类及其 Layout HomeKeyObserverReceiver 类 FloatWindowUtils 类 总结 Android 弹窗浅谈 我们知道 Android 弹窗中,有一类弹窗会在应用之外也显示,这是因为他被申明成了系统弹窗,除此之外还有2类弹窗分别是

  • Kotlin与Java相互调用的完整实例

    目录 一.Kotlin 调用 Java 二.Java 调用 Kotlin 附 Github 源码: 总结 一.Kotlin 调用 Java 1. kotlin 关键字转义 java 中的方法或变量 是 kotlin 的关键字时,使用反引号 `` 对关键字进行转义 // java public class JavaDemo { String is; public String getIs() { return is; } public void setIs(String is) { this.is

  • Kotlin协程启动createCoroutine及创建startCoroutine原理

    目录 createCoroutine 和 startCoroutine startCoroutine调用 createCoroutineUnintercepted intercepted resume 结语 createCoroutine 和 startCoroutine 协程到底是怎么创建和启动的?本篇文章带你揭晓. 在Continuation.kt文件中,有2个基础API,这里单独提出来说一下,方便后面我们理解launch. public fun <T> (suspend () ->

  • kotlin源码结构层次详解

    目录 协程源码的结构 基础层 中间层 平台层 协程源码的结构 在研究Kotlin源码之前,得先搞懂Kotlin源码结构分布.不然找不到该看哪里的代码.看源码之前当然先得有一个目标,最好是带着这个目标去看源码才比较有针对性,抓主流程,不然可能会陷入浩瀚的源码细节中. 协程源码,按道理可以分成2个仓库,一个是Kotlin仓库,一个是Kotlin协程仓库. Kotlin仓库 https://github.com/JetBrains/kotlin 协程仓库 kotlinx.coroutines http

  • java协程框架quasar和kotlin中的协程对比分析

    目录 前言 快速体验 添加依赖 添加javaagent 线程VS协程 协程代码 多线程代码 协程完胜 后记 前言 早就听说Go语言开发的服务不用任何架构优化,就可以轻松实现百万级别的qps.这得益于Go语言级别的协程的处理效率.协程不同于线程,线程是操作系统级别的资源,创建线程,调度线程,销毁线程都是重量级别的操作.而且线程的资源有限,在java中大量的不加限制的创建线程非常容易将系统搞垮.接下来要分享的这个开源项目,正是解决了在java中只能使用多线程模型开发高并发应用的窘境,使得java也能

  • Kotlin协程launch原理详解

    目录 正文 launch使用 launch原理 CoroutineStart中找invoke方法 startCoroutineCancellable逻辑 小结 正文 launch我们经常用,今天来看看它是什么原理. 建议: 食用本篇文章之前记得先食用Kotlin协程之createCoroutine和startCoroutine launch使用 launch我们应该很熟悉了,随便举个例子: fun main() { val coroutineScope = CoroutineScope(Job(

  • Python并发编程协程(Coroutine)之Gevent详解

    Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporateroutine的缩写,直接翻译为协同的例程,一般我们都简称为协程. 在linux系统中,线程就是轻量级的进程,而我们通常也把协程称为轻量级的线程即微线程. 进程和协程 下面对比一下进程和协程的相同点和不同点: 相同点: 我们都可以把他们看做是一种执行流,执行流可以挂起,并且后面可以在你挂起的地方恢复执行,这实际上都可以看做是con

  • PHP7下协程的实现方法详解

    前言 相信大家都听说过『协程』这个概念吧. 但是有些同学对这个概念似懂非懂,不知道怎么实现,怎么用,用在哪,甚至有些人认为yield就是协程! 我始终相信,如果你无法准确地表达出一个知识点的话,我可以认为你就是不懂. 如果你之前了解过利用PHP实现协程的话,你肯定看过鸟哥的那篇文章:在PHP中使用协程实现多任务调度| 风雪之隅 鸟哥这篇文章是从国外的作者翻译来的,翻译的简洁明了,也给出了具体的例子了. 我写这篇文章的目的,是想对鸟哥文章做更加充足的补充,毕竟有部分同学的基础还是不够好,看得也是云

  • PHP生成器(generator)和协程的实现方法详解

    本文实例讲述了PHP生成器(generator)和协程的实现方法.分享给大家供大家参考,具体如下: 先说一些废话 PHP 5.5 以来,新的诸多特性又一次令 PHP 焕发新的光彩,虽然在本文写的时候已是 PHP 7 alpha 2 发布后的一段时间,但此时国内依旧是 php 5.3 的天下.不过我认为新的特性迟早会因为旧的版本的逐渐消失而变得越发重要,尤其是 PHP 7 的正式版出来后,因此本文的目的就是为了在这之前,帮助一些 PHPer 了解一些他们从没有了解的东西.所以打算将以本篇作为博客中

  • Java并发编程包中atomic的实现原理示例详解

    线程安全: 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么就称这个类时线程安全的. 线程安全主要体现在以下三个方面: 原子性:提供了互斥访问,同一时刻只能有一个线程对它进行操作 可见性:一个线程对主内存的修改可以及时的被其他线程观察到 有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序的存在,该观察结果一般杂乱无序 引子 在多线程的场景中,我们需要保证数据安全,就会考虑同步的

  • Kotlin的枚举与异常示例详解

    一.kotlin中枚举的定义 枚举需要用到两个关键字 enum class,譬如这样 enum class Color(val r: Int,val g: Int,val b: Int){ //彩虹色也是一个典故:韦克菲尔德战役 RED(255,0,0),ORANGE(255,165,0),YELLOW(255,255,0), GREEN(0,255,0),BLUE(0,0,255),INDIGO(75,0,130),VIOLET(238,130,238); fun rgb() = (r * 2

  • Python 异步协程函数原理及实例详解

    这篇文章主要介绍了Python 异步协程函数原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一. asyncio 1.python3.4开始引入标准库之中,内置对异步io的支持 2.asyncio本身是一个消息循环 3.步骤: (1)创建消息循环 (2)把协程导入 (3)关闭 4.举例: import threading # 引入异步io包 import asyncio # 使用协程 @ asyncio.coroutine def

  • java中Servlet监听器的工作原理及示例详解

    监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行. 监听器原理 监听原理 1.存在事件源 2.提供监听器 3.为事件源注册监听器 4.操作事件源,产生事件对象,将事件对象传递给监听器,并且执行监听器相应监听方法 监听器典型案例:监听window窗口的事件监听器 例如:swing开发首先制造Frame**窗体**,窗体本身也是一个显示空间,对窗体提供监听器,监听窗体方法调用或者属性改变:

  • Python网络爬虫中的同步与异步示例详解

    一.同步与异步 #同步编程(同一时间只能做一件事,做完了才能做下一件事情) <-a_url-><-b_url-><-c_url-> #异步编程 (可以近似的理解成同一时间有多个事情在做,但有先后) <-a_url-> <-b_url-> <-c_url-> <-d_url-> <-e_url-> <-f_url-> <-g_url-> <-h_url-> <--i_ur

  • 使用kotlin协程提高app性能(译)

    协程是一种并发设计模式,您可以在Android上使用它来简化异步执行的代码.Kotlin1.3版本添加了 Coroutines,并基于其他语言的既定概念. 在Android上,协程有助于解决两个主要问题: 管理长时间运行的任务,否则可能会阻止主线程并导致应用冻结. 提供主安全性,或从主线程安全地调用网络或磁盘操作. 本主题描述了如何使用Kotlin协程解决这些问题,使您能够编写更清晰,更简洁的应用程序代码. 管理长时间运行的任务 在Android上,每个应用程序都有一个主线程来处理用户界面并管理

  • JavaScript作用域示例详解

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域示例详解的介绍,希望能帮助大家更好的学习JavaScript. 任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期.在JavaScript中,变量的作用域有全局作用域和局部作用域两种. 一.JavaScript中无块级作用域 在Java或C#中存在块级作用域

随机推荐

其他