在Kotlin中,如何在保持结构化并发能力的同时使用参与者?
我有一个类,它使用参与者来确保共享可变状态的线程安全。我为这个演员做了一个小包装,使其易于使用:在Kotlin中,如何在保持结构化并发能力的同时使用参与者?,kotlin,kotlin-coroutines,kotlin-multiplatform,Kotlin,Kotlin Coroutines,Kotlin Multiplatform,我有一个类,它使用参与者来确保共享可变状态的线程安全。我为这个演员做了一个小包装,使其易于使用: interface Ref<T : Any> { fun get(): T fun transform(transformer: (T) -> T): Job } transform在没有运行阻塞的情况下执行类似的操作,只返回一个作业: 在转换调用导致另一个调用之前,这是正常的: ref.transform { ... ref.transform
interface Ref<T : Any> {
fun get(): T
fun transform(transformer: (T) -> T): Job
}
transform在没有运行阻塞的情况下执行类似的操作,只返回一个作业:
在转换调用导致另一个调用之前,这是正常的:
ref.transform {
...
ref.transform {
}
}
在这里,我有两份工作,但没有办法将它们合并为一份工作,如果我想等待它们完成,我可以调用join
解决这个问题的方法是结构化并发,但是我不知道如何创建我的actor,因为它被定义为CoroutineScope上的一个扩展
如何在保持使用结构化并发的能力的同时继续使用actor
请注意,我之所以创建Ref,是因为我的项目是多平台的,对于JVM以外的目标,我使用替代实现。actor按照添加项目的相同顺序处理项目,并在单个协同程序中按顺序执行。这意味着内部转换将在外部转换完成后进行处理,当您在actor中使用actor时,您不能对其进行更改。我们不能启动更多的协程,因为我们将状态限制在单个线程中,否则可能会重复处理顺序。如果我们将转换标记为挂起函数,尝试将内部转换的作业加入到外部转换的主体中,只会导致死锁
你同意这种行为吗?如果不是,则不要使用参与者或嵌套变换。如果是,请提供一些用例,其中创建将在外部转换后处理的嵌套转换是有意义的
至于加入所有的工作,我有一些代码。大体上,我们有一个外部转换,它创建了一个内部转换。外部一个返回2,内部一个返回8,但是内部一个在外部一个完成后开始,所以结果是8。但正如您所希望的,transformJob.join main也会等待内部作业
私人封闭式再造林
私有类Getval延迟:CompletableDeferred:重新操作
私有类Transformval transformer:TransformStub.T->T,val stub:TransformStub,val作业:CompletableJob:重新操作
接口参考{
乐趣:T
有趣的transformtransformer:TransformStub.T->T:Job
}
接口转换存根{
有趣的transformtransformer:TransformStub.T->T:Job
}
私有类转换
val演员:SendChannel,
val范围:CoroutineScope
:转换存根{
覆盖transformtransformer:TransformStub.T->T:Job{
返回范围.launch{
val childJob:CompletableJob=Job
val childStub=transformstubimpactor,此
actor.sendTransformer、childStub、childJob
childJob.join
}
}
}
类重新填充初始值:T:Ref{
private val actorJob=作业
私有val actorScope=CoroutineScopeactorJob
private val actor=actorScope.actor{
变量值:T=初始值
频道中的味精{
当味精{
是Get->{
printlget!$value
msg.deferred.completevalue
}
是转换->{
味精{
val newValue=stub.transformervalue
printlnTransform!$value->$newValue
值=新值
工作完成了
}
}
}
}
}
覆盖乐趣获取:T=runBlocking{
val deferred=CompletableDeferred
actor.sendGetdeferred
等待
}
覆盖transformtransformer:TransformStub.T->T:Job{
val存根=TransformStubImpactor,GlobalScope
回线变压器
}
}
fun main=运行阻塞{
val ref:ref=RefImpl0
val transformJob=ref.transform{
变换{8}
2.
}
转换job.join
ref.get
}
actor按照添加项目的相同顺序处理项目,并在单个协同程序中按顺序执行。这意味着内部转换将在外部转换完成后进行处理,当您在actor中使用actor时,您不能对其进行更改。我们不能启动更多的协程,因为我们将状态限制在单个线程中,否则可能会重复处理顺序。如果我们将转换标记为挂起函数,尝试将内部转换的作业加入到外部转换的主体中,只会导致死锁
你同意这种行为吗?如果不是,则不要使用参与者或嵌套变换。如果是,请提供一些用例,其中创建将在外部转换后处理的嵌套转换是有意义的
至于加入所有的工作,我有一些代码。大体上,我们有一个外部转换,它创建了一个内部转换。外一个返回2,内一个返回8,但内一个在外一个完成后开始
一,结果是8。但正如您所希望的,transformJob.join main也会等待内部作业
私人封闭式再造林
私有类Getval延迟:CompletableDeferred:重新操作
私有类Transformval transformer:TransformStub.T->T,val stub:TransformStub,val作业:CompletableJob:重新操作
接口参考{
乐趣:T
有趣的transformtransformer:TransformStub.T->T:Job
}
接口转换存根{
有趣的transformtransformer:TransformStub.T->T:Job
}
私有类转换
val演员:SendChannel,
val范围:CoroutineScope
:转换存根{
覆盖transformtransformer:TransformStub.T->T:Job{
返回范围.launch{
val childJob:CompletableJob=Job
val childStub=transformstubimpactor,此
actor.sendTransformer、childStub、childJob
childJob.join
}
}
}
类重新填充初始值:T:Ref{
private val actorJob=作业
私有val actorScope=CoroutineScopeactorJob
private val actor=actorScope.actor{
变量值:T=初始值
频道中的味精{
当味精{
是Get->{
printlget!$value
msg.deferred.completevalue
}
是转换->{
味精{
val newValue=stub.transformervalue
printlnTransform!$value->$newValue
值=新值
工作完成了
}
}
}
}
}
覆盖乐趣获取:T=runBlocking{
val deferred=CompletableDeferred
actor.sendGetdeferred
等待
}
覆盖transformtransformer:TransformStub.T->T:Job{
val存根=TransformStubImpactor,GlobalScope
回线变压器
}
}
fun main=运行阻塞{
val ref:ref=RefImpl0
val transformJob=ref.transform{
变换{8}
2.
}
转换job.join
ref.get
}
override fun transform(transformer: (T) -> T): Job {
val job = Job()
launch {
actor.send(RefOperation.Transform(transformer, job))
}
return job
}
ref.transform {
...
ref.transform {
}
}