Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala Monix如何使用flatMap操作符的背压?_Scala_Backpressure_Monix - Fatal编程技术网

Scala Monix如何使用flatMap操作符的背压?

Scala Monix如何使用flatMap操作符的背压?,scala,backpressure,monix,Scala,Backpressure,Monix,Monix使用Ack来同步发出的消息,但如果我使用groupBy和flatMap,则内部可观察对象不会跟随源的背压 请参阅此测试代码: import java.util.concurrent.TimeUnit import monix.execution.Scheduler.Implicits.global import monix.execution.Ack.Continue import monix.reactive.{Observable, OverflowStrategy} impor

Monix使用Ack来同步发出的消息,但如果我使用groupBy和flatMap,则内部可观察对象不会跟随
源的背压

请参阅此测试代码:

import java.util.concurrent.TimeUnit

import monix.execution.Scheduler.Implicits.global
import monix.execution.Ack.Continue
import monix.reactive.{Observable, OverflowStrategy}
import org.junit.Test


class MonixBackpressureWithGroupByTest2 {
  @Test
  def test(): Unit = {
    val source = Observable.range(0,130)

    val backPressuredStream = source.map(x => {
        println("simple log first  map - " + x)
        x
      })
      .asyncBoundary(OverflowStrategy.BackPressure(5))
      .map { i =>

        println("after backpressure map, and Rim 3 operation of source - " + ((i % 3) toString) -> i)
        ((i % 3) toString) -> i
      }
      .groupBy{case (k, v) => k}
      .flatMap(x => {
        val mapWithSleep = x.map{case groupedMsg@(key, value) =>
          Thread.sleep(2000)
          println("inner Observable after group by rim 3. sleep 2 second for every message - " + groupedMsg)
          groupedMsg
        }

        mapWithSleep

      })

    backPressuredStream.share.subscribe(
      (keyAndValue: (String, Long)) => Continue
    )

    global.scheduleWithFixedDelay(0L, 1000L, TimeUnit.MILLISECONDS, () => {
      println("========sleep 1 second ============")
    })

    Thread.currentThread().join()

  }

}
输出:

...

========sleep 1 second ============
inner Observable after group by rim 3. sleep 2 second for every message - (0,72)
(after backpressure map, and Rim 3 operation of source - 1,73)
(after backpressure map, and Rim 3 operation of source - 2,74)
(after backpressure map, and Rim 3 operation of source - 0,75)
========sleep 1 second ============
========sleep 1 second ============
inner Observable after group by rim 3. sleep 2 second for every message - (0,75)
(after backpressure map, and Rim 3 operation of source - 1,76)
(after backpressure map, and Rim 3 operation of source - 2,77)
(after backpressure map, and Rim 3 operation of source - 0,78)
========sleep 1 second ============
========sleep 1 second ============
inner Observable after group by rim 3. sleep 2 second for every message - (0,78)
(after backpressure map, and Rim 3 operation of source - 1,79)
...
其中出现一些背压不匹配:
之后:
为每条消息睡眠2秒钟…
背压在背压映射之后给出三个
项-…

在背压映射之后,
如何为每条消息睡眠2秒…
在背压方面有一对一的关系-…

另一个疑问是:为什么日志中的
每一条消息都要睡眠2秒钟
输出
(0,72),(0,75),(0,78)
,但是这样的事情
(0,72),(1,73),(2,74)

谢谢

Monix版本:
“io.monix”%%“monix”%%“3.0.0-RC1”

您看到的行为正是您所期望的

为了快速总结您的应用程序的功能,让我用我的话来解释一下:


您有一个
可观察的
生成数字,并对每个元素执行一些副作用

接下来,按
\u3
对元素进行分组

接下来,在每组的
可观察到的
中再做一些副作用(睡眠和写入控制台)

然后,您将
flatMap
每个组的
可观察的
,生成一个单一的、平面的
可观察的


那么,为什么一开始只看到第一组(其中
\u%3==0
)将内容打印到控制台***

答案在于
flatMap
:当查看可观察的
时,您会发现
flatMap
的以下描述:

final def flatMap[B](f: (A) ⇒ Observable[B]): Observable[B]

Alias for concatMap.

[...]
想象一下可观察的
列表,就像你想一秒钟
列表那样:当你关注
列表
s时,你会得到一个单一的
列表
,首先包含第一个
列表
的元素,然后是第二个
列表
的元素,依此类推

在Monix中,通过等待在
flatMap
(读取:
concatMap
)操作中生成的第一个
可观察的
发送“已完成”信号,可以实现
可观察的
的相同行为。只有这样,第二个
可观察的
才会被消耗,依此类推

或者简单地说,
flatMap
关心生成的
可观察的
s的顺序。

但是您的
flatMap
操作中的
Observable
s何时“完成”?为此,我们必须了解
groupBy
是如何工作的,因为这就是它们的来源

对于
groupBy
来说,尽管
Observable
s是惰性评估的,但它必须将传入元素存储在缓冲区中。我对此不是100%确定,但是如果
groupBy
像我认为的那样工作,它将,对于任何拉动下一个元素的分组
可观察的
,无限期地遍历原始
可观察的
,直到它找到属于该组的元素,保存所有之前的元素(但不是必需的)属于该缓冲区中其他组的元素,以供以后使用

所有这一切意味着
groupBy
在源
Observable
发出完成信号之前无法知道是否找到了组中的所有元素,然后它将使用所有剩余的缓冲元素,然后向分组
Observable
发出完成信号

简单地说:
Observable
groupBy
生成的
s在源
Observable
完成之前不完成。

当将所有这些信息汇总在一起时,您将了解到,只有当源可观测值(您的
可观测范围(0130)
)完成时,第一个分组的
可观测值也将完成,并且由于
平面图
的原因,只有当所有其他分组的
可观测值
将被使用

因为我从你的上一个问题知道,你正在尝试构建一个web套接字,使用
flatMap
是一个坏主意-你的源
可观察的
传入请求永远不会完成,实际上只服务于你遇到的第一个IP地址

您需要做的是使用
mergeMap
concatMap
mergeMap
相比,它不关心元素的顺序,而是使用“先到先得”规则



***:当你读完我的解释,并希望理解
groupBy
flatMap
的工作原理时,你就会明白我为什么写“在开头”

你问题中的语法错误使你很难理解你在问什么。因为我们都是人,没有人希望你能说(或写)一口流利的英语,你能至少试着用更详细的方式解释一下吗?也许也可以不写
线程-
2222-
=====
,让你的日志信息更具描述性,这样我们就可以理解你想要表达的内容了。@MarkusAppel,你好,我做了一些漂亮的打印信息和变量名。尽管如此,很抱歉英语也很差。谢谢你的耐心!正如您所说,在构建套接字库时出现了问题。保留。
mergeMap
对于每个套接字来说都是一个很好的选择,作为分组事件的一个可观察对象。关于groupBy的另一个想法是如何取消订阅断开连接的套接字,避免缓冲区无效,如果远程地址作为组密钥,则可观察?@LoranceChen我认为这在很大程度上取决于您首先如何将套接字包装成
可观察的
。但是如果您合并分组的
可观察的
s,您将无法取消对单个组的订阅-因为所有内容只有一个
订户
。但你可能不需要退订——它不会带来任何真正的小鬼