Coroutines框架学习——协程间通信(一)

Channel

Channel是协程间的管道通信方式,数据之间只能支持一对一的传输关系,如果想要实现一对多的关系,请使用broadcast。

Channel的构建:   

public fun <E> Channel(
    capacity: Int = RENDEZVOUS, // 数据容量大小
    onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND, // 协程数据超过capacity后的状态 
    onUndeliveredElement: ((E) -> Unit)? = null  // 没有接收者的回调
)

Channel在创建时可以指定他的capacity(数据容量)模式,它的模式见下:

模式

取值

描述

UNLIMITED
Int.MAX_VALUE
无限容量的管道

RENDEZVOUS(默认)

0无容量的管道。

CONFLATED

-1保留最新,receive只能获得最近一次send的值
BUFFERED-2默认容量,可通过程序参数设置默认大小,默认为64。当管道中的数据量达到64时挂起。
”FIXED“(固定值)1~x固定容量,通过参数执行缓存大小,当管道中的数据量达到缓存值时挂起。

协程数据超过capacity后发送者状态由BufferOverflow来决定:

模式

取值

描述

SUSPEND协程直接挂起无限容量,send调用后直接返回。
DROP_OLDEST丢弃掉最久的数据不见不散,send调用后挂起直到receive到达。
DROP_LATEST丢弃掉最新的数据保留最新,receive只能获得最近一次send的值

onUndeliveredElement当数据没有接收者接收时会被动性的调用

注:

  • CONFLATED模式下只能设置onBufferOverflow == BufferOverflow.SUSPEND

  • CONFLATED模式等价于Channel<E>(Channel.RENDEZVOUS,BufferOverflow.DROP_LATEST)

使用方法:

val channel_unlimited = Channel<Int>(Channel.UNLIMITED)
val channel_rendezvous = Channel<Int>(Channel.RENDEZVOUS,BufferOverflow.DROP_LATEST)
val channel_conflated = Channel<Int>(
    Channel.CONFLATED,
    BufferOverflow.SUSPEND
) { println("onUndeliveredElement i=${it}") }
val channel_buffered = Channel<Int>(Channel.BUFFERED)
val channel_fixed = Channel<Int>(3)

var channel_select = channel_rendezvous

val produce = GlobalScope.launch {
    for(i in 0..10){
        channel_select.send(i)
    }
}

val consumer = GlobalScope.launch {
    while (!channel_select.isClosedForReceive){
        val value = channel_select.receiveOrNull()
        println(value)
    }
}

Build模式:

Coroutines中提供了两种简单的构建者模式(produce和actor)来帮助我们快速的构建Channel。

模式

描述

produce启动一个生产者协程,返回ReceiveChannel
actor启动一个消费者卸载,返回SendChannel

示例:

suspend fun producer(){
    val receiveChannel = GlobalScope.produce<Int>(capacity = Channel.UNLIMITED) {
        for(i in 0..3){
            send(i)
        }
    }
}
 
suspend fun consumer(){
    val sendChannel = GlobalScope.actor<Int>(capacity = Channel.UNLIMITED) {
        for(i in 0..3){
            println(receive())
        }
    }
}

broadcast(广播):

当发送者与接收者的关系为一对多时适用,广播的数据会发送给所有的接收者。

注:广播由于不需要等待接收方响应,所以不可使用RENDEZVOUS模式

示例:

suspend fun broadcast(){
    val broadcastChannel = GlobalScope.broadcast<Int>(capacity = Channel.UNLIMITED) {
        for(i in 0..3){
            send(i)
        }
    }
 
    List(5){
        GlobalScope.launch {
            val receiveChannel = broadcastChannel.openSubscription()
            for(i in receiveChannel){
                println(i)
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity协程的底层实现是基于C#的迭代器实现的。在C#中,使用yield关键字可以将方法转换为迭代器,通过迭代器可以实现协程的效果。Unity中的协程也是基于这个原理实现的。 如果要自己实现一个协程,可以按照以下步骤进行: 1. 定义一个委托,用于表示协程的执行体。 ```csharp public delegate IEnumerator CoroutineDelegate(); ``` 2. 定义一个协程类,保存协程的执行体和当前执行状态。 ```csharp public class Coroutine { private CoroutineDelegate m_CoroutineDelegate; private IEnumerator m_Enumerator; private bool m_IsDone; public bool IsDone { get { return m_IsDone; } } public Coroutine(CoroutineDelegate coroutineDelegate) { m_CoroutineDelegate = coroutineDelegate; m_Enumerator = m_CoroutineDelegate(); m_IsDone = false; } public void Update() { if (m_Enumerator != null && !m_IsDone) { if (!m_Enumerator.MoveNext()) { m_IsDone = true; } } } } ``` 3. 在需要使用协程的地方,创建一个协程对象并添加到一个协程管理器中。 ```csharp public class CoroutineManager : MonoBehaviour { private static CoroutineManager m_Instance; private List<Coroutine> m_Coroutines = new List<Coroutine>(); public static CoroutineManager Instance { get { if (m_Instance == null) { m_Instance = new GameObject("CoroutineManager").AddComponent<CoroutineManager>(); } return m_Instance; } } private void Update() { for (int i = m_Coroutines.Count - 1; i >= 0; i--) { Coroutine coroutine = m_Coroutines[i]; coroutine.Update(); if (coroutine.IsDone) { m_Coroutines.RemoveAt(i); } } } public Coroutine StartCoroutine(CoroutineDelegate coroutineDelegate) { Coroutine coroutine = new Coroutine(coroutineDelegate); m_Coroutines.Add(coroutine); return coroutine; } } ``` 4. 在协程中使用yield关键字来实现挂起和恢复。 ```csharp private IEnumerator MyCoroutine() { Debug.Log("Start Coroutine"); yield return null; Debug.Log("Wait One Frame"); yield return new WaitForSeconds(1.0f); Debug.Log("Wait One Second"); yield return new WaitForEndOfFrame(); Debug.Log("Wait End Of Frame"); } ``` 以上就是一个简单的协程实现。注意,实际应用中还需要考虑协程的取消、异常处理等问题,需要根据具体需求进行扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值