java – 通过拆分和运行将ListenableFuture>转换为Iterable>

前端之家收集整理的这篇文章主要介绍了java – 通过拆分和运行将ListenableFuture>转换为Iterable>前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在寻找转换ListenableFuture的最佳方法< Iterable< A>>成为一系列单独的ListenableFutures.这是我正在寻找的方法签名:
public <A,B> Iterable<ListenableFuture<B>> splitAndRun(
    final ListenableFuture<Iterable<A>> elements,final Function<A,B> func,final ListeningExecutorService executor
);

很明显,如果我返回ListenableFuture< Iterable< ListenableFuture< B>>>,我可以这样做,但我觉得我应该能够拆分并运行它并保持其异步性.

这是我到目前为止的代码,但你会注意到最后讨厌的.get(),它会破坏事物.如果我的事情过于复杂,请原谅.

public class CallableFunction<I,O> implements Callable<O>{
  private final I input;
  private final Function<I,O> func;

  public CallableFunction(I input,Function<I,O> func) {
    this.input = input;
    this.func = func;
  }

  @Override public O call() throws Exception {
    return func.apply(input);
  }
}

public <A,final ListeningExecutorService executor
) throws InterruptedException,ExecutionException {
  return Futures.transform(elements,new Function<Iterable<A>,Iterable<ListenableFuture<B>>>() {
    @Override
    public Iterable<ListenableFuture<B>> apply(Iterable<A> input) {
      return Iterables.transform(input,new Function<A,ListenableFuture<B>>() {
        @Override
        public ListenableFuture<B> apply(A a) {
          return executor.submit(new CallableFunction<A,B>(a,func));
        }
      });
    }
  },executor).get();
}

解决方法

(替代 my original answer)

但是,如果转型是缓慢的,或者某些输入可能会失败但是对其他输入成功会怎么样?在这种情况下,我们希望单独转换每个输出.另外,我们希望确保转换只发生一次.我们的集合转换方法不能保证这一点.因此,在您的示例代码中,输出上的每次迭代都会向执行程序提交新任务,即使先前提交的任务可能已经完成.因此,只有在转换是轻量级的时候,我们才推荐Iterables.transform和朋友. (通常,如果你正在做重量级的事情,你的转换函数将抛出一个已检查的异常,函数不允许.考虑这个提示:)当然,你的例子不会触发提示.)

这在代码中意味着什么?基本上,我们将颠倒我在其他答案中给出的操作顺序.我们将转换为Future< Iterable< A>>到Iterable< Future< A>>第一.然后我们将为每个A提交一个单独的任务,将其转换为B.对于后一步,我们将提供Executor so that the transformation doesn’t block some innocent thread.(我们现在只需要Futures.transform,所以我静态导入它. )

List<ListenableFuture<A>> individuals = newArrayList();
for (int i = 0; i < knownSize; i++) {
  final int index = i;
  individuals.add(transform(input,new Function<List<A>,A>() {
    @Override
    public A apply(List<A> values) {
      return values.get(index);
    }
  }));
}

List<ListenableFuture<B>> result = newArrayList();
for (ListenableFuture<A> original : individuals) {
  result.add(transform(original,function,executor));
}
return result;

无论如何,那就是这个想法.但我的实施是愚蠢的.我们可以轻松地同时执行这两个步骤:

List<ListenableFuture<B>> result = newArrayList();
for (int i = 0; i < knownSize; i++) {
  final int index = i;
  result.add(transform(input,B>() {
    @Override
    public B apply(List<A> values) {
      return function.apply(values.get(index));
    }
  },executor));
}
return result;

因为这使得n Futures.transform调用而不是1并且因为它使用单独的Executor,所以如果转换是重量级的,那么它比我的其他解决方案更好,如果它是轻量级的则更糟.另一个警告仍然是:只有当你知道你将拥有多少输出时,这才有效.

猜你在找的Java相关文章