Kotlin协程上下文与调度器

Kotlin协程上下文与调度器,第1张

协程总是运行在⼀些以 CoroutineContext 类型为代表的上下文中,它们被定义在了 Kotlin 的标准库里。协程上下文是各种元素的集合,其中主要元素是协程中的Job(前面提到lanch和async都会返回一个job)

协程上下文包含⼀个协程调度器(参见 CoroutineDispatcher)它确定了相关的协程在哪个线程或哪些线程上执行。协程调度器可以将协程限制在⼀个特定的线程执行,或将它分派到⼀个线程池,亦或是让它不受限地运行。

所有的协程构建器诸如 launch 和 async 接收⼀个可选的 CoroutineContext 参数,它可以被用来显式的为⼀个新协程或其它上下文元素指定⼀个调度器。

DispatchersUnconfined 协程调度器在调用它的线程启动了⼀个协程,但它仅仅只是运行到第⼀个挂起点。挂起后,它恢复线程中的协程,而这完全由被调用的挂起函数来决定。非受限的调度器非常适用于执行不消耗 CPU 时间的任务,以及不更新局限于特定线程的任何共享数据(如UI)的协程。 另⼀方面,该调度器默认继承了外部的 CoroutineScope。runBlocking 协程的默认调度器,特别是,当它被限制在了调用者线程时,继承自它将会有效地限制协程在该线程运行并且具有可预测的 FIFO 调度。

所以该协程的上下文继承自 runBlocking {} 协程并在 main 线程中运行,当 delay 函数调用的时候,非受限的那个协程在默认的执行者线程中恢复执行

协程可以在⼀个线程上挂起并在其它线程上恢复。如果没有特殊工具,甚至对于⼀个单线程的调度器也是难以弄清楚协程在何时何地正在做什么事情。

让线程在每⼀个日志文件的日志声明中打印线程的名字,用log函数就行

协程可在不同的线程中跳转。使用 runBlocking 来显式指定了⼀个上下文,并且另⼀个使用 withContext 函数来改变协程的上下文,而仍然驻留在相同的协程中。不需要某个在 newSingleThreadContext 中创建的线程的时候,使用 use 函数来释放该线程。

协程的 Job 是上下文的⼀部分,并且可以使用 coroutineContext [Job] 表达式在上下文中检索它。CoroutineScope 中的 isActive 只是 coroutineContext[Job]isActive == true 的⼀种方便的快捷方式。(在协程取消时有提到,使计算协程可退出)

当⼀个协程被其它协程在 CoroutineScope 中启动的时候,它将通过 CoroutineScopecoroutineContext 来承袭上下文,并且这个新协程的 Job 将会成为父协程作业的子作业。当⼀个父协程被取消的时候,所有它的子协程也会被递归的取消。

当使用 GlobalScope 来启动⼀个协程时,则新协程的作业没有父作业。因此它与这个启动的作用域无关且独立运作。

⼀个父协程总是等待所有的子协程执行结束。父协程并不显式的跟踪所有子协程的启动,并且子协程不必使用 Jobjoin

当协程经常打印日志并且你只需要关联来⾃同⼀个协程的日志记录时,则自动分配的 id 是非常好的。然而,当⼀个协程与特定请求的处理相关联时或做⼀些特定的后台任务,最好将其明确命名以用于调试目的。

CoroutineName 上下文元素与线程名具有相同的目的。当调试模式开启时,它被包含在正在执行此协程的线程名中。

有时我们需要在协程上下文中定义多个元素。我们可以使用 + *** 作符来实现

kotlinxcoroutines 提供了⼀个封装:CoroutineScope 的抽象。所有的协程构建器都声明为在它之上的扩展。

创建⼀个 CoroutineScope 实例来管理协程的生命周期,并使它与 activity 的生命周期相关联。CoroutineScope 可以通过 CoroutineScope() 创建或者通过MainScope() 工厂函数。前者创建了⼀个通用作用域,而后者为使用 DispatchersMain 作为默认调度器的 UI 应用程序创建作用域:

输出:

前三个协程打印了消息,而其它的协程在 Activitydestroy() 调用了 cancel()

ThreadLocal,asContextElement 扩展函数可以将⼀些线程局部数据传递到协程与协程之间。asContextElement 它创建了额外的上下文元素,且保留给定 ThreadLocal 的值,并在每次协程切换其上下文时恢复它。

使用 DispatchersDefault 在后台线程池中启动了⼀个新的协程,所以它工作在线程池中的不同线程中,但它仍然具有线程局部变量的值,我们指定使用 threadLocalasContextElement(value = "launch") ,无论协程执行在哪个线程中都是没有问题的。

threadLocal有⼀个关键限制,即:当⼀个线程局部变量变化时,则这个新值不会传播给协程调用者(因为上下文元素无法追踪所有 ThreadLocal 对象访问),并且下次挂起时更新的值将丢失。使用 withContext 在协程中更新线程局部变量, 详见asContextElement。

输出

对象

对象对象是已命名的数据集合。其中“已命名的数据”指的就是它的属性和方法,如:

var a = { val : 1 , func:function(){}}

对象 a 拥有两个已命名的数据 val 和 func 。

访问对象的成员可以使用 或 [ ] ,其中 运算符要求它右边必须是合法的标示符,而 [ ] 运算符,对它的 *** 作数并无要求,任何合法的值都可以,如:

aval ; // 1

afunc() ; // undefined ;

a["x"] = 2 ; // a : { val : 1 , func:function(){} , x : 2 }

a[null] = 3 ; // a : { val : 1 , func:function(){} , x : 2 ,null : 3}

2原型

对象有一个私有的属性 __proto__,持有其原型的引用。

对象的原型,也是一个对象。对象与它的原型的关系就是:数据共享,这体现在对象属性值的查找过程。访问对象的属性,首先在它自定义的数据集合中寻找,找到后,立即返回该值;如果没有找到,则到它的原型中寻找,找到后,立即返回值;;如果一直到原型链(原型还可以有原型)的末端都没有找到,则返回 undefined。

var b = { bPro : "in b" } ;

a__proto__ = b ;

alert( abPro ) ; // in b ;

如果一个对象没有显式的指定原型,那么它的原型默认是 Objectprototype ,而 Objectprototype__proto__ = null ,所以它就是所有原型链的结尾。

为对象添加了一个在原型中存在的属性,则会覆盖对原型属性的访问。

abPro = "in a" ;

alert(abPro) ; // "in a"

alert(a__proto__bPro) ; // "in b"

可以看到,修改对象,并未影响到原型,更不会影响到共享同一个原型的其他对象。

3 构造函数

任何函数都可以用作构造函数,只要使用 new 运算符进行调用即可。

构造函数的原理,就是创建一个对象,并将函数的属性 prototype 赋给刚刚创创建的这个对象的 __proto__ 属性、传递原型,然后将 this 指向它;执行函数体,函数体中形如 thisx = y 的代码都是在给这个刚创建的对象添加成员;最后这个新创建的对象会作为 new 表达式的值返回。如下:

function obj(xValue){

   thisx = xValue ;

}

objprototype = { pro : "in prototype" } ;

var a = new obj(1) ; // { x : 1 }

alert(apro) ; // "in prototype" 

a__proto__ === objprototype // true;

当然,函数也可以返回值。但只有 Object 类的实例(包括子类实例)才会生效,其他的值都会被忽略,继续返回刚创建的对象(即使函数体中一个 this 都么有)。

function func( ret ){

    thisx = 5 ;

    return ret;

}

var a = new func() ; // { x : 5 } 

var b = new func( null ) ; // { x : 5 } 

var c = new func( { } ) ; // { } 

var d = new func( [] ) ; // [] 

var e = new func( 1 ) ; // { x : 5 } 

var f = new func( new Number( 1 ) ) ; // Number

4 Bulalalal

后面的我没看懂,查了查,发现内容也没啥新鲜的。

如果一个拥有返回值,且返回的是 Object 类的实例(包括子类实例),那么使用不使用 new 运算符的结果都是一样的。同其他语言中一样,具有这样功能函数,都叫做工厂函数,更复杂的创建过程可能不叫这个名字,但也一定会包括"工厂"二字。

function obj(x , y ){

     return { proX : x , proY : y } ;

}

虽然说懂了原理,其他的都是形式问题。但其实我也觉得有必要深入了解一下,毕竟和人交流的时候,不能让一些其实没多大意义的名词给难住、影响沟通效果。

只是我有点累了,手指头快麻了,我去瞅瞅别的东西了。(还有,我已不做程序员好多年,新东西学不动了)

参考文章:对象 >

以上就是关于Kotlin协程上下文与调度器全部的内容,包括:Kotlin协程上下文与调度器、JavaScript对象和原型和构造函数怎么理解、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10091429.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存