理解 .NET Core中的Channel篇之三——理解背压

本文探讨.NET中Channel的Bounded模式,介绍如何通过设置`BoundedChannelOptions`实现背压管理,包括FullMode选项和关键方法如`WaitToWriteAsync`、`TryWrite`。通过银行排队和公路交通的比喻解释背压概念,以及通道在处理流控中的作用。
摘要由CSDN通过智能技术生成

这篇文章是.NET中有关Channel的系列文章的一部分。当然,最好从第1部分开始,但是您可以使用下面的链接跳过任何想要的地方。这系列文章均是本人翻译,翻译也是随性而至,并非直译,英文好的可以去看原文,译文可以随便转载,但请注明出处!

1、复习

上一篇讲到无限队列,读写分离,线程安全,还有优雅的循环读取通道数据,以及获取通道关闭的信号,当然了,你应该还记得我们这样建立通道。

var myChannel = Channel.CreateUnbounded<int>();

“那,有没有有限队列呢?”

“ 是的,又被你猜中了,有!”

var myChannel = Channel.CreateBounded<int>(1000);

这与创建容量有限的其他集合类型(如列表或数组)并不太相似。

在我们的示例中,我们创建了一个最多可容纳1000个项目的通道。

好好的,为什么要限制自己呢?

嗯…这就是背压的来源。

2、什么是背压

在计算方面(特别是在消息传递/排队方面),背压是一种思想。因为计算机中,无论是内存,ram,网络容量还是所需外部API的API速度都受到一定的制约。所以我们应该能够在链条上施加“压力”,以减轻一些负担,至少,要让生态系统中的其他人知道我们正在承受负载,我们可能需要一些时间来处理他们的请求。

当然,谈到背压,一般就会提到流控,背压只是解决流控的其中一个方案而已。

就像小学做的那道数学题:一个水池,一个进水管和一个出水管。如果进水管水流更大,过一段时间水池就会溢出。这就是没有流控导致的结果。

而解决流控(Flow Control)有几种思路呢?

  1. 背压(Backpressure),就是消费者需要多少,生产者就生产多少。这有点类似于TCP里的流量控制,接收方根据自己的接收窗口的情况来控制接收速率,并通过反向的ACK包来控制发送方的发送速率。这种方案只对于cold Observable有效。cold Observable是那些允许降低速率的发送源,比如两台机器传一个文件,速率可大可小,即使降低到每秒几个字节,只要时间足够长,还是能够完成的。相反的例子就是音视频直播,速率低于某个值整个功能就没法用了(这种类似于hot Observable)。
  2. 节流(Throttling),说白了就是丢弃。消费不过来,就处理其中一部分,剩下的丢弃。至于处理哪些和丢弃哪些,就有不同的策略,也就是采样sample (or throttleLast)、throttleFirst、debounce (or throttleWithTimeout)这三种。还是举音视频直播的例子,在下游处理不过来的时候,就需要丢弃数据包。
  3. 打包(buffer和window)。buffer和window基本一样,只是输出格式不太一样。它们是把上游多个小包裹打成大包裹,分发到下游。这样下游需要处理的包裹的个数就减少了。
  4. 阻塞住整个调用链(Callstack blocking),是一种特殊情况。之所以说这是一种特殊情况,是因为这种方式只适用于整个调用链都在一个线程上同步执行,这要求中间的各个operator都不能启动新的线程。在平常使用中这种应该是比较少见的,因为我们经常使用subscribeOn或observeOn来切换执行线程,而且有些复杂的operator本身也会内部启动新的线程来处理。另外,如果真的出现了完全同步的调用链,前面的(1)(2)(3)仍然有可能适用的,只不过这种阻塞的方式更简单,不需要额外的支持。

举个例子比较一下(1)和(4)。(4)相当于很多车行驶在盘山公路上,而公路只有一条车道。那么排在最前面的第一辆车就挡住了整条路,后面的车也只能排在后面。而(1)相当于银行办业务时的窗口叫号,窗口主动叫某个号过去(相当于请求),那个人才过去办理。

那么,.NET通道如何工作?

3、通道的背压选项

当使用通道时,我们实际上有一个非常简单的方法来增加背压。代码看起来是这样的:

var channelOptions = new BoundedChannelOptions(5)
{
    FullMode = BoundedChannelFullMode.Wait
};

var myChannel = Channel.CreateBounded<int>(channelOptions);

FullMode可以有一下几种选项:

  • Wait
    发布者能调用WriteAsync()之前,简单的处于等待状态。
  • DropNewest/DropOldest
    扔掉最老的/最新的消息,为继续的写入消息腾出空间。
  • DropWrite
    丢掉想写的消息,反正已经写不进去了。

4、还有2种需要注意的方法

还有2个方法,需要关注下:

await myChannel.Writer.WaitToWriteAsync();

这让我们“等待”通道的大小限制,满足写条件。

例如,当通道已满时,会等待直到有新的空间,这意味着即使打开了DropWrite FullMode方式,我们也可以通过简单地等待直到有容量来限制我们丢弃的消息量。

还有一个代码:

var success = myChannel.Writer.TryWrite(i);

这使我们能够尝试写入队列,并返回是否成功。

重要提示,此方法不是异步的。

不管我们是否可以写入该通道,都没有“嗯。如果再等一会,您可能可以”。

5、小结

选择这个专题,也是为了共同熟悉,共同进步!关注楼主,不迷路,我是网尘。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值