[英]Generate infinite sequence of Natural numbers using RxJava
我正在尝试使用RxJava编写一个简单的程序来生成无限的自然数序列。 所以,到目前为止,我已经找到了两种使用Observable.timer()和Observable.interval()生成数字序列的方法。 我不确定这些功能是否是解决此问题的正确方法。 我期待像Java 8中那样的简单函数来生成无限的自然数。
IntStream.iterate(1,value - > value +1)。forEach(System.out :: println);
我尝试使用带有Observable的IntStream,但这不能正常工作。 它只向第一个用户发送无限的数字流。 如何正确生成无限自然数序列?
import rx.Observable;
import rx.functions.Action1;
import java.util.stream.IntStream;
public class NaturalNumbers {
public static void main(String[] args) {
Observable<Integer> naturalNumbers = Observable.<Integer>create(subscriber -> {
IntStream stream = IntStream.iterate(1, val -> val + 1);
stream.forEach(naturalNumber -> subscriber.onNext(naturalNumber));
});
Action1<Integer> first = naturalNumber -> System.out.println("First got " + naturalNumber);
Action1<Integer> second = naturalNumber -> System.out.println("Second got " + naturalNumber);
Action1<Integer> third = naturalNumber -> System.out.println("Third got " + naturalNumber);
naturalNumbers.subscribe(first);
naturalNumbers.subscribe(second);
naturalNumbers.subscribe(third);
}
}
问题是naturalNumbers.subscribe(first);
,你实现的OnSubscribe
被调用,你正在一个无限的流上做一个forEach
,因此你的程序永远不会终止。
您可以处理它的一种方法是在不同的线程上异步订阅它们。 为了轻松查看结果,我不得不在Stream处理中引入一个sleep:
Observable<Integer> naturalNumbers = Observable.<Integer>create(subscriber -> {
IntStream stream = IntStream.iterate(1, i -> i + 1);
stream.peek(i -> {
try {
// Added to visibly see printing
Thread.sleep(50);
} catch (InterruptedException e) {
}
}).forEach(subscriber::onNext);
});
final Subscription subscribe1 = naturalNumbers
.subscribeOn(Schedulers.newThread())
.subscribe(first);
final Subscription subscribe2 = naturalNumbers
.subscribeOn(Schedulers.newThread())
.subscribe(second);
final Subscription subscribe3 = naturalNumbers
.subscribeOn(Schedulers.newThread())
.subscribe(third);
Thread.sleep(1000);
System.out.println("Unsubscribing");
subscribe1.unsubscribe();
subscribe2.unsubscribe();
subscribe3.unsubscribe();
Thread.sleep(1000);
System.out.println("Stopping");
Observable.Generate
正是反应性地解决这类问题的运算符。 我还假设这是一个教学示例,因为使用迭代可能更好。
您的代码在订阅者的线程上生成整个流。 由于它是无限流,因此subscribe
呼叫永远不会完成。 除了那个明显的问题之外,取消订阅也会有问题,因为你没有在你的循环中检查它。
您希望使用调度程序来解决此问题 - 当然不要使用subscribeOn
因为这会给所有观察者带来负担。 将每个号码的发送安排到onNext
- 作为每个预定操作的最后一步,安排下一个。
基本上这就是Observable.generate
为您提供的 - 每次迭代都在提供的调度程序上进行调度(如果您没有指定它,则默认为引入并发的调度程序)。 可以取消调度程序操作并避免线程不足。
Rx.NET像这样解决它(实际上有一个async/await
模型更好,但在Java afaik中不可用):
static IObservable<int> Range(int start, int count, IScheduler scheduler)
{
return Observable.Create<int>(observer =>
{
return scheduler.Schedule(0, (i, self) =>
{
if (i < count)
{
Console.WriteLine("Iteration {0}", i);
observer.OnNext(start + i);
self(i + 1);
}
else
{
observer.OnCompleted();
}
});
});
}
这里有两点需要注意:
self
参数是对用于调用下一次迭代的调度程序的引用。 这允许取消订阅取消操作。 不确定这在RxJava中看起来如何,但这个想法应该是一样的。 同样, Observable.generate
可能对您来说更简单,因为它旨在处理这种情况。
在创建无限顺序时,应注意:
第一个问题是通过使用subscribeOn()
, observeOn()
和各种调度程序来解决的。
第二个问题最好通过使用库提供的方法Observable.generate()
或Observable.fromIterable()
。 他们做了适当的检查。
检查一下:
Observable<Integer> naturalNumbers =
Observable.<Integer, Integer>generate(() -> 1, (s, g) -> {
logger.info("generating {}", s);
g.onNext(s);
return s + 1;
}).subscribeOn(Schedulers.newThread());
Disposable sub1 = naturalNumbers
.subscribe(v -> logger.info("1 got {}", v));
Disposable sub2 = naturalNumbers
.subscribe(v -> logger.info("2 got {}", v));
Disposable sub3 = naturalNumbers
.subscribe(v -> logger.info("3 got {}", v));
Thread.sleep(100);
logger.info("unsubscribing...");
sub1.dispose();
sub2.dispose();
sub3.dispose();
Thread.sleep(1000);
logger.info("done");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.