我有一些非常简单的代码,读了一堆Strings&应用过滤器。我希望过滤器能在多个线程上运行。
Iterable<String> outputs = Observable
.from(Files.readLines(new File("E:\\SAMA\\Test\\ImageNetBullets.txt"), Charset.forName("utf-8")))
.take(20).subscribeOn(Schedulers.from(threadPoolExecutor)).filter(str -> isURLOK(str))
.toBlocking().toIterable();
从日志中可以看出,Filter方法只在一个线程上运行:
In Thread pool-1-thread-1
In Thread pool-1-thread-1
http://farm2.static.flickr.com/1258/1479683334_3ff920d217.jpg
In Thread pool-1-thread-1
In Thread pool-1-thread-1
如何加快速度?
答案 0 :(得分:5)
RxJava本质上是顺序的。例如,使用map(Func1)
,Func1
本身将与通过父序列的值非并发执行:
Observable.range(1, 10).map(v -> v * v).subscribe(System.out::println);
这里,lambda v - &gt; v * v将以顺序方式调用值1到10。
RxJava可以以管道中的阶段(范围 - > map-&gt; subscribe)相对于彼此同时/并行发生的方式异步。例如:
Observable.range(1, 10)
.subscribeOn(Schedulers.computation())
.map(v -> v * v) // (1)
.observeOn(Schedulers.io())
.map(v -> -v) // (2)
.toBlocking()
.subscribe(System.out::println); // (3)
这里,(1)可以与(2)和(3)并行运行,即,(2)计算av = 3 * 3,(1)可能已经计算v = 5并且(3)打印出来-1
在同一时间。
如果您想同时处理序列的元素,您必须将序列“分叉”到子Observable
s,然后将结果与flatMap
联接起来:
Observable.range(1, 10)
.flatMap(v ->
Observable.just(v)
.subscribeOn(Schedulers.computation())
.map(v -> v * v)
)
.toBlocking()
.subscribe(System.out::println);
这里,每个值v
将启动一个在后台线程上运行的新Observable
,并通过map()进行计算。 v = 1
可以在线程1上运行,v = 2
可以在线程2上运行,v = 3
可以在线程1上运行,但严格地在计算v = 1
之后运行。
答案 1 :(得分:2)
对.subscribeOn
的调用只是确定将启动Scheduler
观察点(并且对于您的示例,所有排放将在调度程序提供的一个线程上传播)。
如果您没有太多工作要处理流中的每个项目,那么处理可能由IO主导,因此并行处理可能无济于事。
一般来说,虽然一种方法是将流缓冲到块中并处理flatMap
上订阅的Schedulers.computation()
内的每个块:
Observable<String> outputs =
lines
.buffer(1000)
.flatMap(list ->
Observable
.from(list)
//do something computationally expensive
.filter(line -> intensive(line))
.subscribeOn(Schedulers.computation()));
使用buffer
是因为调度大量工作所需的开销比安排大量微小任务要少。