【问题标题】:Process a list of IO intensive tasks in parallel with RxJava与 RxJava 并行处理 IO 密集型任务列表
【发布时间】:2015-02-03 10:04:02
【问题描述】:

我需要并行获取一些文件。 get 操作本身是 IO 密集型的,可以从并行执行中受益匪浅。

使用 RxJava,我可以通过使用 Async.toAsync 包装我的函数来实现这一点。

我想知道使用subscribeOn()observeOn() 是否有更简洁的方法?我无法弄清楚。尝试了不同的方式,但任何方式都只能使用一个线程,并且处理是按顺序进行的。

import rx.Observable;
import rx.Scheduler;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import rx.util.async.Async;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class ParallelMultiGet {

    public List<String> readContents(List<String> paths) {

        Func1<String, String> getFunction = new Func1<String, String>() {
            @Override
            public String call(String path) {
                return get(path);
            }
        };

        Scheduler scheduler = Schedulers.from(
                Executors.newFixedThreadPool(
                        Math.min(paths.size(), 50)));

        Future<List<String>> result = Observable
                .from(paths)
                .flatMap(
                        Async.toAsync(getFunction, scheduler))
                .toList()
                .toBlocking()
                .toFuture();
        try {
            return result.get(30, TimeUnit.MINUTES);
        } catch (Exception e) {
            // For example if Func1.call above throws an exception it ends up in here
            throw new IllegalStateException("Couldn't read paths", e);
        }
    }

    private String get(String path) {
        // this would be the slow operation, waiting for IO
        return "content";
    }

}

即使这已经很不错了,因为我不需要构建自己的循环来提交期货并将它们中的值组合到结果列表中。但也许不必这么冗长?

【问题讨论】:

  • 你不需要异步;只是一个普通的ExecutorService.invokeAll()
  • 这里确实值得一提。结果是 List,因此仍需要至少对其进行迭代并将值映射到列表中。 invokeAll() 的整体复杂性较低,但这个问题主要是关于如何使用 RxJava 来完成。很高兴找到一种方便的方法链接方式,并且能够使用Observable.from等而不是“手动”迭代paths来为invokeAll()创建任务。

标签: java asynchronous reactive-programming observable rx-java


【解决方案1】:

为了不那么冗长:

  • 你可以使用 RxJava 中的超时操作符
  • 您可以将 java8 与 lambda 一起使用,而不是 Func1(但对您的情况没有多大帮助)
  • 您可以避免创建自己的执行程序

我得到了应该和你做同样事情的代码:

  public List<String> readContents(List<String> paths) {

      try {

        return Observable
                .from(paths)
                .flatMap(Async.toAsync((Func1<String, String>) this::get, Schedulers.io()))
                .toList()
                .timeout(30, TimeUnit.MINUTES)
                .toBlocking().single();
      } catch (RuntimeException ex) { // the cause will be a timeoutException
        // For example if Func1.call above throws an exception it ends up in here
        throw new IllegalStateException("Couldn't read paths", ex);
      }
    }

    private String get(String path) {
        // this would be the slow operation, waiting for IO
        return "content";
   }

【讨论】:

  • 谢谢,差不多了。 Async.toAsync 对我来说仍然有点笨拙,但如果这就是 RxJava 的做法,那很好。Schedulers.io() 的问题是它会创建无限数量的线程。另一方面,Schedulers.computation() 限制为 4 个线程(或者这可能取决于内核数量)。这确实是另一个问题,将Schedulers 扩展为类似Schedulers.fixed(int size) 甚至更好的Schedulers.cached(int maxSize) 会相当简单。
  • .timeout() + .single() 很漂亮。感谢您的提示。
  • 您可以使用重载的 flatMap(),它将最大并发订阅的 observable 数量作为第二个参数。
猜你喜欢
  • 2020-06-16
  • 2016-06-04
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-09
  • 1970-01-01
  • 2017-11-12
相关资源
最近更新 更多