orb-slam2深入研究_深入研究流程和渠道-第3部分:渠道

orb-slam2深入研究

Spanish version

西班牙语版本

This text is based on 1.3.7 version of kotlinx.coroutines library

本文基于kotlinx.coroutines库的1.3.7版本

So now we know what is a Stream (and its types) and how Flows works (and, again, if you don’t, check the previous articles, links below). Now, let’s discover our second Kotlin Stream implementation: Channels.

因此,现在我们知道什么是Stream(及其类型)以及Flows的工作方式(如果没有,请再次检查前面的文章,下面的链接)。 现在,让我们发现第二个Kotlin Stream实现:Channels。

Again, you can see some examples by checking the GitHub Repository. There are very small and simple cases that will help you to understand how to use Channels and some other stuff.

同样,您可以通过查看GitHub Repository来查看一些示例。 有一些非常简单的案例可以帮助您了解如何使用Channel和其他一些东西。

Remember that this article belongs to a series:

请记住,本文属于系列文章:

Before we start, let me give you a warning: this article will be a bit extense. If you feel that you’re not understanding something, please take a break and return to this later. This is all you need to understand how Channels work, so give yourself time!

在开始之前,让我警告您:这篇文章会有点冗长。 如果您觉得自己不了解某些内容,请稍事休息,稍后再返回。 这就是您了解频道如何工作所需的全部内容,请给自己一些时间!

Let’s go with part three: Channels!

让我们继续第三部分: 频道

频道 (Channels)

什么是频道? (What is a Channel?)

A Channel is used to establish a connection between a sender and a receiver. It can be closed and all the operations related to them are suspendable.

通道用于在发送方和接收方之间建立连接 。 它可以关闭,并且与它们有关的所有操作都可以挂起

The first big difference with Flows is that they can start emitting values no matter if there is someone listening to them or not.

Flows的第一个主要区别是, 无论是否有人在听 ,它们都可以开始发出值

Also, as you can access a Channel through its reference, you can emit and receive values wherever you want (or wherever you have the reference). If we compare this with Flows, where we only can emit values from inside a Flow’s block, here we have a huge difference too.

另外,由于您可以通过其引用访问通道,因此可以在任何需要的地方(或具有引用的地方) 发射和接收值 。 如果将它与Flows进行比较,则Flows只能从Flow的内部发出值,这里我们也有很大的不同。

So, with those characteristics, we can assume that Channels are Hot Streams.

因此,根据这些特征,我们可以假设频道为热门视频流

Behind the scenes, it’s just an interface that implements two other interfaces: SendChannel and ReceiveChannel. In that implementation, we will find the key points on how Channels work.

在幕后,它只是一个实现其他两个接口的接口: SendChannelReceiveChannel 。 在该实现中,我们将找到有关渠道如何工作的关键点。

public interface Channel<E> : SendChannel<E>, ReceiveChannel<E> {
  ...
}

A diagram that can explain at a high level what is a Channel is the next one:

下一张图可以从更高层次解释什么是频道:

Image for post

Here, we can see that:

在这里,我们可以看到:

  • There is a Sender that puts some data inside a Buffer. This is done with SendChannel operations.

    有一个发送器 ,它将一些数据放入Buffer中 。 这是通过SendChannel操作完成的。

  • There is a Receiver that obtains data from the Buffer. This is done with ReceiveChannel operations.

    有一个ReceiverBuffer获取数据。 这是通过ReceiveChannel操作完成的。

  • There is a Buffer, that helps us synchronizing the Sender and the Receiver. Remember Roman’s article and the mention of synchronization? Well, this is what he was talking about.

    有一个缓冲区 ,可以帮助我们同步发送方接收方 。 还记得Roman的文章和提及同步的内容吗? 好吧,这就是他在说的。

We can say that the above diagram represents a Channel and its behaviour.

可以说,上图表示一个Channel及其行为。

频道的寄件者 (Channel’s Sender)

The SendChannel interface represents the Channel’s sender, as we said before. It defines the sender’s behaviour or, in other words, how a Channel emits values.

如前所述,SendChannel接口代表Channel的发送者 。 它定义了发送者的行为,换句话说,定义了Channel如何发出值

public interface SendChannel<in E> {
  
  public val isClosedForSend: Boolean
  
  public suspend fun send(element: E)
  public fun offer(element: E): Boolean


  public fun close(cause: Throwable? = null): Boolean
  public fun invokeOnClose(handler: (cause: Throwable?) -> Unit)
  
}

Let’s review what do we have here:

让我们回顾一下我们在这里有什么:

  • The isClosedForSend attribute that returns if the Channel is closed and cannot send more data. If you try to send something, you will get a ClosedSendChannelException exception.

    isClosedForSend属性,如果Channel已关闭并且无法发送更多数据,则返回该属性。 如果尝试发送某些内容,则会收到ClosedSendChannelException异常。

  • The send() and offer() methods are used to emit values. And, if we remember well, they’re the same that we used on channelFlows, right?

    send()offer()方法用于发出值。 而且,如果我们还记得的话,它们与我们在channelFlows上使用的相同,对吗?

  • The close() method is used to close the Channel’s Sender. And pay special attention here: only the Channel’s Sender. We’ll revisit this statement later.

    close()方法用于关闭通道的发件人。 并在此特别注意: 频道的发件人。 稍后我们将重新讨论该声明。

  • The invokeOnClose() method is invoked automatically when the Sender closes or the Receiver gets cancelled.

    当发送方关闭或接收方被取消时,会自动调用invokeOnClose()方法。

And that’s what we need to know for now. Let’s review some things about the Sender actor.

这就是我们现在需要知道的。 让我们回顾一下有关Sender演员的一些事情。

发送值—要offer()还是send()? (Sending values — To offer() or to send() ?)

We said that these methods are used to emit values. But, wait, why do we have two methods to put data in the buffer? Let’s clarify:

我们说过,这些方法用于发出值。 但是,等等,为什么我们有两种方法将数据放入缓冲区 ? 让我们澄清一下:

The offer() method adds an element to the buffer immediately if possible. By saying if possible we mean “if we don’t violate the channel’s capacity” (or, in other words, the buffer exists and is not full).

报价() 方法在可能的情况下立即将元素添加到缓冲区如果可能,我们说的是“如果我们不违反通道的容量” (或者换句话说,缓冲区存在且未满)。

Also, if we check SenderChannel’s interface, we can see that offer() returns a Boolean: true if the element can be added, false if not.

另外,如果我们检查SenderChannel的接口,我们可以看到offer()返回一个布尔值:如果可以添加元素,则返回true,否则返回false。

On the other hand, we have the send() method. Here, if the buffer is not full, the element is added immediately, just like offer(). But, what happens if the buffer is full or it doesn’t exist? Well, the send() caller gets suspended.

另一方面,我们有send()方法。 在此,如果缓冲区未满,则立即添加元素,就像offer()一样 。 但是,如果缓冲区已满或不存在会怎样? 好吧, send()调用者被暂停

So, the main difference here is that send() is a suspendable operation, and it helps to synchronize the sender and the receiver. We don’t have a return here, instead, we get suspended.

因此,这里的主要区别在于send() 是一个可挂起的操作 ,它有助于同步发送方和接收方。 我们在这里没有退货,相反,我们被停职了。

In summary:

综上所述:

  • If you want to send a value (or try to send) without waiting, use offer(). Take into account that, maybe, the value will never reach the buffer.

    如果要不等待就发送值(或尝试发送),请使用offer() 。 考虑到该值可能永远不会到达缓冲区。

  • If you want that value to be received by someone, and you can wait until that someone appears, use send().

    如果希望某人接收该值,并且可以等到该人出现,请使用send()

频道的接收者 (Channel’s Receiver)

The ReceiveChannel interface represents the Channel’s receiver, as we mentioned before. It defines the receiver’s behaviour or, in other words, how we can listen to Channel’s emissions.

如前所述, ReceiveChannel接口代表通道的接收器 。 它定义了接收器的行为,或者换句话说, 就是我们如何收听Channel的发射

public interface ReceiveChannel<out E> {
  
  public val isClosedForReceive: Boolean
  
  public suspend fun receive(): E
  public fun poll(): E?


  public fun cancel(cause: CancellationException? = null)
  
}

Let’s review what do we have here:

让我们回顾一下这里的内容:

  • The isClosedForReceive attribute returns if the receiver cannot get any more values. When a channel is closed for receive? It will be discussed later because it’s not as simple as you can imagine. Wait a bit more!

    如果接收者无法获得更多值,则返回isClosedForReceive属性。 当通道关闭以进行接收时 ? 稍后将对其进行讨论,因为它并不像您想象的那么简单。 再等等!

  • The receive() and poll() methods are used to receive values from the buffer.

    receive()poll()方法用于从缓冲区接收值。

  • The cancel() method is used to stop the reception of all the elements on the buffer, removing the ones that were not sent (cleaning the buffer).

    cancel()方法用于停止接收缓冲区中的所有元素,并删除未发送的元素(清理缓冲区)。

There is some other stuff in the interface, but it’s not so important. If you want to dig into it, you can check the docs.

界面中还有一些其他内容,但并不重要。 如果您想深入研究它,可以检查文档。

接收值—轮询()还是接收()? (Receiving values — To poll() or to receive() ?)

Here, like for sending, we have two methods too. Why? Well, maybe you are thinking about the difference between offer() and send(), and you’re in the right way because we have something similar.

在这里,就像发送一样,我们也有两种方法。 为什么? 好吧,也许您正在考虑offer()send()之间的区别,并且您的方法正确,因为我们有类似的地方。

The poll() method obtains an element synchronously. If the buffer has something inside, that something is returned. What happens if the buffer is empty? Simple: it returns null.

poll()方法同步获取元素 。 如果缓冲区内部有东西,则返回一些东西 。 如果缓冲区为空会怎样? 简单: 返回null

On the other hand, we have the receive() method, and this one obtains an element asynchronously. If the buffer has something inside, we get that something. But, if the buffer is empty or it doesn’t exist, the receive() caller gets suspended, until a new value is posted to the buffer.

另一方面,我们具有receive()方法,并且该方法异步获取元素 。 如果缓冲区内部有东西,我们就会得到东西 。 但是,如果缓冲区为空或不存在, 则receive()调用方将被挂起 ,直到将新值发布到缓冲区中为止。

So, the main difference here is that receive() is a suspendable operation, and this is another mechanism used for synchronizing the sender and the receiver.

因此,这里的主要区别是receive()是可挂起的操作 ,这是用于同步发送方和接收方的另一种机制。

In summary:

综上所述:

  • If you want to receive a value (or try to receive) without waiting, use poll(). Take into account that, maybe, you will not receive a value.

    如果要不等待而接收值(或尝试接收),请使用poll() 。 考虑到您可能不会获得价值。

  • If you want to receive a real value, and you can wait until that value appears, use receive().

    如果要接收真实值,并且可以等待该值出现,请使用receive()

通道是否关闭以供接收? (Is the Channel closed for receive?)

For us to be sure that a Channel is closed for receive, there are two conditions that must be satisfied:

为了确保关闭通道以进行接收必须满足两个条件

  • Someone invoked SendChannel.close(), so the Channel is closed for send.

    有人调用了SendChannel.close() ,因此关闭了该通道以进行send

  • All the items sent to the buffer have been received by a Receiver, so the buffer is empty. If the buffer is not empty, the Channel is still not closed for receive.

    发送到缓冲区的所有项目均已由接收方接收,因此缓冲区为空。 如果缓冲区不为空,则通道仍未关闭以进行接收

So, if we close the Channel’s sender but the buffer has items inside, then the Channel will not be closed for receive until all that items have been sent.

因此,如果我们关闭Channel的发送方,但是缓冲区内部有项目,那么直到所有这些项目都发送完之后,Channel才会关闭以供接收。

关闭还是取消? (Closing or Cancelling?)

If we paid attention, we see that both Sender and Receiver have methods to “close” them: SendChannel.close() and ReceiveChannel.cancel(). What’s the difference?

如果我们注意的话,我们会发现Sender和Receiver都有“关闭”它们的方法: SendChannel.close()ReceiveChannel.cancel() 。 有什么不同?

Well, I create a table that compares both methods and their side effects. Check it out!

好吧,我创建了一个表,将两种方法及其副作用进行了比较。 看看这个!

Image for post

As you can see, there are several differences. We must take care of which method we use.

如您所见,存在一些差异。 我们必须注意使用哪种方法

Next, we will see what can happen when we close a Channel because, of course, this is very very simple and we need some more complicated stuff, right? 🙃

接下来,我们将看到关闭Channel时会发生什么,因为这当然非常简单,并且我们需要一些更复杂的东西,对吗? 🙃

封闭通道和故障通道 (Closed Channels and Failed Channels)

There is something more when we call SendChannel.close() method.

当我们调用SendChannel.close()方法时,还有更多东西。

Depending on how we call it (with a cause or not) we can have two different states: closed or failed. Just to clarify, when I say a cause I mean an exception (if we look at the SenderChannel’s interface, we will see that close() method can receive an exception).

根据我们如何称呼它(是否有原因 ), 我们可以有两种不同的状态:关闭或失败 。 只是为了澄清一下,当我说一个原因时,我是指一个异常(如果我们查看SenderChannel的接口,我们将看到close()方法可以接收一个异常)。

Again, I make a table to explain the difference between them:

同样,我制作了一张表格来说明它们之间的区别:

Image for post

I think that the most important difference is what happens when we try to call poll().

我认为最重要的区别是,当我们尝试调用poll()时会发生什么。

There is one last thing that we have to know: if we call ReceiveChannel.cancel() with a cause, we will have a Failed Channel too, because that cause is sent to SendChannel.close().

我们要知道的最后一件事: 如果我们用一个原因调用ReceiveChannel.cancel(),我们也会有一个失败的通道 ,因为该原因被发送到SendChannel.close()

Enough theory (yes?), let’s create some Channels!

理论足够(是吗?),让我们创建一些渠道!

建立频道 (Creating Channels)

All Channels are created with a factory function

所有通道均使用出厂功能创建

public fun <E> Channel(capacity: Int = RENDEZVOUS): Channel<E> =
    when (capacity) {
        RENDEZVOUS -> RendezvousChannel()
        UNLIMITED -> LinkedListChannel()
        CONFLATED -> ConflatedChannel()
        BUFFERED -> ArrayChannel(CHANNEL_DEFAULT_CAPACITY)
        else -> ArrayChannel(capacity)
    }


val myChannel = Channel<String>()

According to the value we send on the capacity parameter, we can create several kinds of channels. We can see those types in the when clause.

根据我们在容量参数上发送的值, 我们可以创建几种通道 。 我们可以在when子句中看到这些类型。

The Channels have different behaviours according to their type. There are two main differences between them:

通道根据其类型具有不同的行为。 它们之间有两个主要区别:

  • The buffer capacity.

    缓冲能力

  • How they manage buffer values.

    他们如何管理缓冲区值

To explain how they work, I’ll use the send() and receive() methods, because they suspend the callers and, with that, we can see how the synchronization works on each channel.

为了解释它们是如何工作的,我将使用send()receive()方法,因为它们会挂起调用者,然后,我们可以看到同步在每个通道上的工作方式。

交会通道 (Rendezvous Channel)

This is the Channel that we get if we don’t specify the capacity, and we create it with this snippet:

如果不指定容量 ,这就是我们获得的频道,并使用以下代码段创建它:

val myChannel = Channel<String>()
val myChannel = Channel<String>(Channel.RENDEZVOUS)

The channel’s instance type is RendezvousChannel.

通道的实例类型为RendezvousChannel

The buffer capacity of this channel is 0. What does it mean? Well, we can say that the channel doesn’t have capacity, or in other words, the buffer doesn’t exist.

该通道的缓冲区容量为0 。 这是什么意思? 好吧,我们可以说该通道没有容量 ,换句话说, 该缓冲区不存在

As a rule, we say that the elements are sent only when the sender and the receiver meet.

通常,我们说元素只有在发送者和接收者相遇时才发送

Technically:

技术上:

  • All send() callers get suspended until some receive() caller appears.

    所有send()调用者都将被挂起,直到出现某些receive()调用者。

  • All receive() callers get suspended until some send() caller appears.

    所有的receive()调用者都将被挂起,直到出现某些send()调用者。

I send you homework! What happens if we only use offer() with this Channel? Go and find it yourself!

我给你发作业! 如果我们仅与此频道一起使用offer() ,会发生什么? 自己去找吧!

缓冲通道 (Buffered Channel)

We create them with this snippet:

我们使用以下代码片段创建它们:

val channel = Channel<String>(Channel.BUFFERED)

The channel’s instance type is ArrayChannel.

通道的实例类型为ArrayChannel

The buffer capacity of this channel is 64, and that’s the default capacity configured in the JVM (we can change it, but we don’t need it).

该通道的缓冲区容量为64这是 JVM中配置的默认容量(我们可以更改它,但不需要它)。

Technically:

技术上:

  • All send() callers get suspended if the buffer is full, and that means there are 64 elements on it.

    如果缓冲区已满,则所有send()调用者都将挂起,这意味着上面有64个元素。

  • All receive() callers get suspended if the buffer is empty.

    如果缓冲区为空,则所有receive()调用者都将被挂起。

With the help of this Channel, we introduce a general rule:

在此频道的帮助下,我们引入了一条通用规则

In all the Channels, no matter its type, the receive() callers get suspended always if the buffer is empty.

在所有Channel中,无论其类型如何,如果缓冲区为空, receive()调用程序都会始终挂起。

Maybe it was a bit difficult to see with the Rendezvous Channel, but with the Buffered one, we can see it more explicitly.

在“集合点通道”中可能很难看到它,但是在“缓冲通道”中,我们可以更清楚地看到它。

无限频道 (Unlimited Channel)

We create them with this snippet:

我们使用以下代码片段创建它们:

val channel = Channel<String>(Channel.UNLIMITED)

The channel’s instance type is LinkedListChannel.

通道的实例类型为LinkedListChannel

With this channel, we have a buffer whose capacity is unlimited. But, as we know, there is no such thing as unlimited on the real world, so actually our limit is the available memory we have.

通过此通道, 我们有一个容量不受限制的缓冲区 。 但是,正如我们所知,在现实世界中没有无限的东西,因此实际上我们的限制是我们拥有的可用内存

Technically:

技术上:

  • All send() callers never get suspended, because, in theory, the buffer is never full.

    所有send()调用方都不会挂起,因为从理论上讲,缓冲区永远不会满。

  • All receive() callers get suspended if the buffer is empty.

    如果缓冲区为空,则所有receive()调用者都将被挂起。

合并频道 (Conflated Channel)

We create them with this snippet:

我们使用以下代码片段创建它们:

val channel = Channel<String>(Channel.CONFLATED)

The channel’s instance type is ConflatedChannel.

通道的实例类型为ConflatedChannel

With this channel, we also have a buffer whose capacity is unlimited, like the Unlimited one.

通过此通道, 我们还有一个容量不受限制的缓冲区 ,例如Unlimited。

So, what’s the difference if the buffer is the same as the Unlimited? Well, this channel has a peculiarity: it always offers the last value sent to the buffer, discarding the ones that were not received by anyone. The receiver always gets the most recently sent element. So, we can say that actually the buffer is not really unlimited, because it needs capacity for only one element.

那么,如果缓冲区与Unlimited相同,会有什么区别? 好的,此通道具有一个特殊性: 它总是提供发送到缓冲区的最后一个值,并丢弃任何人未接收到的值接收者总是获取最近发送的元素 。 因此,我们可以说实际上缓冲区并不是真正无限的,因为它只需要一个元素的容量。

But, quiet, this doesn’t mean that the Channel offers at any time the last value. If that value was consumed, it will be removed from the buffer and this one will become empty.

但是,安静, 这并不意味着Channel随时提供最后一个值 。 如果消耗了该值,将从缓冲区中将其删除,并且该值将为空。

Technically:

技术上:

  • All send() callers never get suspended.

    所有send()调用者都不会暂停。

  • All receive() callers get suspended if the buffer is empty.

    如果缓冲区为空,则所有receive()调用者都将被挂起。

定制渠道 (Customized Channel)

We create them with this snippet:

我们使用以下代码片段创建它们:

val channel = Channel<String>(10)
val channel = Channel<String>(15)
val channel = Channel<String>(300)

The channel’s instance type is ArrayChannel.

通道的实例类型为ArrayChannel

The buffer capacity of this channel is the one we send to the factory function. In this case, we get buffers with a capacity of 10, 15 and 300 elements.

该通道的缓冲容量是我们发送给工厂功能的缓冲容量 。 在这种情况下,我们将获得容量为10、15和300个元素的缓冲区。

It works like a Buffered Channel, so I’ll not explain the technics behind it. This is just a Buffered Channel with the capacity that we want or need.

它的工作方式类似于缓冲通道,因此我将不解释其背后的技术。 这只是具有我们想要或需要的容量的缓冲通道。

Athis one.

一个这个

Another recommendation is that you check the GitHub Repository examples, so you can see how the Channels emit and receive values.

另一个建议是,您检查GitHub Repository示例,以便了解Channel如何发出和接收值。

消费价值 (Consuming values)

Let’s talk a bit about the consumption of the buffer’s elements. I will not explain how to put data on it because we achieve this by just calling send() or offer() methods, but, for consuming data, there are some things that need to be clarified.

让我们来谈谈缓冲区元素的消耗。 我不会解释如何在其上放置数据,因为我们只是通过调用send()offer()方法来实现此目的,但是对于使用数据,需要澄清一些事情

As we saw, we can consume data from the channel using poll() and receive(). But, the important thing here is that those methods return only one value. So, if we want to consume more than 1 value, we have to wrap the call in a, for example, while(true) block (or something similar).

如我们所见,我们可以使用poll()receive()来消耗通道中的数据。 但是,重要的是这些方法仅返回一个值 。 因此,如果我们要使用多个值,则必须将调用包装在例如while(true)块(或类似内容)中。

Here we can see a big difference with Flows, where we can collect all the emissions performed by them with just a single terminal operator.

在这里,我们可以看到与Flows有很大的区别 ,在这里我们可以仅由一个终端操作员收集它们执行的所有排放。

Fortunately, we have a solution for this: we can use the Flow’s power to consume the Channel values. There is an extension function, consumeAsFlow(), that, as the name suggests, let us consume the channel emissions as a Flow.

幸运的是,我们有一个解决方案: 我们可以使用Flow的功能来消耗Channel值 。 顾名思义,有一个扩展函数invokeAsFlow() ,让我们将通道发射作为流使用。

val channel = Channel<String>(Channel.BUFFERED)


channel.consumeAsFlow()
  /* you can apply some operators */
  .collect { 
      /* Collect the values! */
  }

What’s happening behind the scenes here? Why can a Channel be a Flow? Let me introduce you to the well-known… ChannelFlow!

这里幕后发生了什么? 为什么通道可以是流? 让我向您介绍著名的… ChannelFlow

public fun <T> ReceiveChannel<T>.consumeAsFlow(): Flow<T>
  = ChannelAsFlow(this, consume = true)


private class ChannelAsFlow<T>(
  ...  
) : ChannelFlow<T>(context, capacity) {
  ...
}

有关消耗数据的更多信息 (Something more on Consuming Data)

There are other methods that we can use. I didn’t talk about them because I think that with poll(), receive() and consumeAsFlow() we have everything we need.

我们可以使用其他方法。 我之所以没有谈论它们,是因为我认为使用poll()receive()consumeAsFlow()可以满足我们的所有需求。

Those methods are:

这些方法是:

  • consume(), but it doesn’t give the element directly.

    消耗() ,但是它不直接给元素。

  • consumeEach(), similar to consumeAsFlow(). In theory, after consuming all the values it cancels the ReceiveChannel, but I tried to reproduce it and I couldn’t.

    consumerEach(),类似于consumerAsFlow() 。 从理论上讲,使用完所有值后,它会取消ReceiveChannel,但我尝试重现它,但我做不到。

  • consumes(), consumesAll(), and others: they are deprecated, or going to be deprecated.

    consumps(),consumesAll()等:它们已被弃用,或将被弃用。

实际用例 (Practical use cases)

In general, any case that can be represented as a publisher-subscriber scenario can be satisfied with the usage of Channels.

通常, 可以使用Channels来满足可以表示为发布者-订阅者方案的任何情况

Then, we may notice one of the biggest differences with Flows: Channels are not scoped to a specific lifecycle. If you want to close/cancel a Channel, you need to explicitly use the methods provided by it. So, if we want to have a stream that survives across screens and lifecycles, then we have to use Channels.

然后,我们可能会注意到与Flows的最大区别之一: 通道的作用域不是特定的生命周期 。 如果要关闭/取消频道,则需要显式使用该频道提供的方法。 因此, 如果我们想拥有一个可以跨屏幕和生命周期生存的流 ,那么我们必须使用Channels。

So, everything alright? Can we end the article now? Well, no. There is something that we haven’t tried yet: having multiple receivers.

那么,一切都还好吗? 我们现在可以结束这篇文章吗? 好吧,不。 我们还没有尝试过的事情: 拥有多个接收器

尝试添加多个接收者 (Trying to add multiple receivers)

Well, if we have a Hot Stream, we have a multicast transmission, right? So, let’s take advantage of that property:

好吧,如果我们有Hot Stream ,就可以进行多播传输,对吗? 因此,让我们利用该属性:

  1. We create a Channel and start sending values to it.

    我们创建一个通道并开始向其发送值。
  2. We attach two receivers.

    我们附上两个接收器。
  3. Both receivers start receiving all the values from the buffer.

    两个接收器都开始从缓冲区接收所有值。

Everything ok, right? Well, no.

一切还好吧? 好吧,不

Channels have a unicast mechanism of transmission, so the receivers won’t get all the buffer’s data. Instead, they will take turns and receive the data in the order they subscribe to the buffer. So, not that hot…

通道具有单播传输机制 ,因此接收器不会获取所有缓冲区的数据。 取而代之的是,它们轮流接收订阅缓冲区中的数据。 所以,不是那么热...

How we can solve this? You’ll have to wait until the next article 😄

我们该如何解决呢? 您必须等到下一篇文章article

这就是现在! (And that’s for now!)

Hope that now you can understand what is a Channel and how it works. There’re a lot of articles out there, so you can keep exploring them to gain more knowledge.

希望您现在可以了解什么是频道及其运作方式。 那里有很多文章,因此您可以继续探索它们以获取更多知识。

In the next article, we’ll talk about Broadcast Channels.

在下一篇文章中,我们将讨论广播频道。

See you later! And, if you like it, you can share!

回头见! 而且,如果您喜欢,可以共享!

Special thanks to the MediaMonks Android team that gives feedback.

特别感谢MediaMonks Android团队提供的反馈。

翻译自: https://proandroiddev.com/going-deep-on-flows-channels-part-3-channels-df150458693b

orb-slam2深入研究

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值