RxJava:merge()是否更改已发出项的顺序?
请看以下两个小测试:RxJava:merge()是否更改已发出项的顺序?,java,functional-programming,rx-java,reactive-programming,rx-java2,Java,Functional Programming,Rx Java,Reactive Programming,Rx Java2,请看以下两个小测试: @Test public void test1() { Observable.range(1, 10) .groupBy(v -> v % 2 == 0) .flatMap(group -> { if (group.getKey()) { return group; } return group; })
@Test
public void test1() {
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.flatMap(group -> {
if (group.getKey()) {
return group;
}
return group;
})
.subscribe(System.out::println);
}
@Test
public void test2() {
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.toMap(g -> g.getKey())
.flatMapObservable(m -> Observable.merge(
m.get(true),
m.get(false)))
.subscribe(System.out::println);
}
我希望两者都能以相同的顺序返回数字列表,因此:
1 2 3 4 5 6 7 8 9 10
但第二个例子又回来了
2 4 6 8 10 1 3 5 7 9
相反
在第二个示例中,merge
执行的是一个concat
,事实上,如果我将其更改为concat
,结果是相同的
我错过了什么
谢谢。基本上
flatMap
和merge
不保证发出项目的顺序
从文件:
请注意,FlatMap合并了这些可见光的发射,以便它们可以交错
从文件:
“合并”可以交错由合并的可观察对象发出的项目(类似的运算符Concat不会交错项目,而是在开始从下一个可观察源发出项目之前,依次发出每个可观察源的所有项目)
引述如下:
在您的例子中,对于单个元素静态流,它不会产生任何真正的区别(但从理论上讲,merge可以以随机顺序输出单词,并且根据规范仍然有效)
如果您需要有保证的订单,请使用concat*
第一个例子
它的工作原理如下:
- 当发出
时,1
操作员将使用键groupBy
false创建一个
GroupedObservable
将从该可观察对象输出项目-当前仅为flatMap
1
- 当发出
时,2
操作员将使用键groupBy
创建一个true
GroupedObservable
现在还将输出第二个flatMap
-当前为GroupedObservable
2
- 当发出
时,3
操作员将使用键groupBy
将其添加到现有的false
中,GroupedObservable
将立即输出此项flatMap
- 当发出
时,4
操作员将使用键groupBy
将其添加到现有的true
中,GroupedObservable
将立即输出此项flatMap
- 等等
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.doOnNext(group -> System.out.println("key: " + group.getKey()))
.flatMap(group -> {
if (group.getKey()) {
return group;
}
return group;
})
.subscribe(System.out::println);
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.doOnNext(group -> System.out.println("key: " + group.getKey()))
.toMap(g -> g.getKey())
.doOnSuccess(map -> System.out.println("map: " + map.size()))
.flatMapObservable(m -> Observable.merge(
m.get(true),
m.get(false)
))
.subscribe(System.out::println);
那么输出是:
key: false
1
key: true
2
3
...
key: false
key: true
map: 2
2
4
6
8
10
1
3
5
7
9
第二个例子
这是完全不同的,因为toMap
将阻塞,直到上游完成:
- 当发出
时,1
操作员将使用键groupBy
false创建一个
GroupedObservable
将此toMap
添加到内部映射,并使用键GroupedObservable
(与false
具有相同的键)GroupedObservable
- 当发出
时,2
操作员将使用键groupBy
创建一个true
GroupedObservable
将此toMap
添加到内部映射中,并使用键GroupedObservable
(与true
的键相同)-因此现在映射有2个GroupedObservable
GroupedObservable
- 将以下数字添加到相应的
中,当源代码完成时,GroupedObservables
操作符完成,并将映射传递给下一个操作符toMap
- 在
中,使用映射创建新的observable,首先添加偶数元素(key=flatMapObservable
),然后添加奇数元素(key=true
)false
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.doOnNext(group -> System.out.println("key: " + group.getKey()))
.flatMap(group -> {
if (group.getKey()) {
return group;
}
return group;
})
.subscribe(System.out::println);
Observable.range(1, 10)
.groupBy(v -> v % 2 == 0)
.doOnNext(group -> System.out.println("key: " + group.getKey()))
.toMap(g -> g.getKey())
.doOnSuccess(map -> System.out.println("map: " + map.size()))
.flatMapObservable(m -> Observable.merge(
m.get(true),
m.get(false)
))
.subscribe(System.out::println);
那么输出是:
key: false
1
key: true
2
3
...
key: false
key: true
map: 2
2
4
6
8
10
1
3
5
7
9
谢谢你的回答,但我还是不明白为什么
merge
内部flatMapObservable
没有保留顺序。现在我知道toMap
正在阻塞,因为它需要知道映射的键,以便在下一阶段发出它在您的情况下,对于单元素静态流,它不会产生任何真正的区别
但是新映射中的2个可观察到的元素不是单元素,是吗?此外,我不确定在这种情况下,static
是什么意思。merge
的定义是元素可能会交错,这是我在本例中所期望的,相反,在flatMapObservable中,元素的行为就像一个concat
在flatMapObservable中,您使用映射创建一个新的observable,首先添加偶数元素(key=true),然后添加奇数元素(key=false)
我想如果我做的是concat
,这是正确的,但我做的是合并
。对,你地图中的两个观测值各有5个元素-但它们是静态的
(即不取决于某个时间)-换句话说:流已经完全定义,所有元素都已知toMap
源流已经完成,映射中的可观察对象可以在订阅时立即输出其所有元素。ad第二条评论:在这种情况下,merge
的行为与concat
相同,这只是巧合。因此,这个merge
实现显然订阅了第一个可观察对象(作为第一个参数传递的内容)并处理其所有数据,然后订阅第二个并处理第二个可观察对象的所有数据。但正如上面提到的:merge
并不能保证这一点。好吧,巧合可能是个错误的词。但我想表达的是,merge
,我们看到的行为依赖于实现。换句话说:其他Rx实现可能有不同的行为——甚至RxJava的更新版本也可能有不同的行为。