组成可变数量的 ListenableFuture
Compose variable number of ListenableFuture
我对 Futures 还很陌生,一直坚持链接调用和创建对象列表。我正在使用 Android,API 最小值是 19。
我想对下面的方法 getAllFoo()
进行编码:
ListenableFuture<List<Foo>> getAllFoo() {
// ...
}
我有这两种方法可用:
ListenableFuture<Foo> getFoo(int index) {
// gets a Foo by its index
}
ListenableFuture<Integer> getNbFoo() {
// gets the total number of Foo objects
}
方法 Futures.allAsList()
在这里可以很好地工作,但我的主要限制是每次调用 getFoo(int index)
只能在前一个完成之前发生。
据我了解(并测试过),Futures.allAsList()
"fans-out" 呼叫(所有呼叫同时开始),所以 我不能使用类似的东西:
ListenableFuture<List<Foo>> getAllFoo() {
// ...
List<ListenableFuture<Foo>> allFutureFoos = new ArrayList<>();
for (int i = 0; i < size; i++) {
allFutureFoos.add(getFoo(i));
}
ListenableFuture<List<Foo>> allFoos = Futures.allAsList(allFutureFoos);
return allFoos;
}
我有这种(丑陋的)解决方案(有效):
// ...
final SettableFuture<List<Foo>> future = SettableFuture.create();
List<Foo> listFoos = new ArrayList<>();
addApToList(future, 0, nbFoo, listFoos);
// ...
private ListenableFuture<List<Foo>> addFooToList(SettableFuture future, int idx, int size, List<Foo> allFoos) {
Futures.addCallback(getFoo(idx), new FutureCallback<Foo>() {
@Override
public void onSuccess(Foo foo) {
allFoos.add(foo);
if ((idx + 1) < size) {
addFooToList(future, idx + 1, size, allFoos);
} else {
future.set(allFoos);
}
}
@Override
public void onFailure(Throwable throwable) {
future.setException(throwable);
}
});
return future;
}
如何使用 ListenableFuture
优雅地实现它?
我找到了多个相关主题(如 this or that),但这些主题使用的是 "coded" 转换,而不是基于可变数量的转换。
如何组合 ListenableFutures
并获得与 Futures.allAsList()
相同的 return 值,但通过链接调用(扇入)?
谢谢!
作为一般规则,与手动 addListener
/ 相比,将衍生期货与 transform
/catching
/whennAllSucceed
/whenAllComplete
链接在一起更好addCallback
来电。转换方法可以为您做更多的事情:
- 减少忘记设置输出从而挂起程序的机会
- 传播取消
- 避免保留内存的时间超过需要的时间
- 采取一些技巧来减少堆栈溢出的机会
无论如何,我不确定是否有一种特别优雅的方法可以做到这一点,但我建议按照以下思路(未经测试!):
ListenableFuture<Integer> countFuture = getNbFoo();
return countFuture.transformAsync(
count -> {
List<ListenableFuture<Foo>> results = new ArrayList<>();
ListenableFuture<?> previous = countFuture;
for (int i = 0; i < count; i++) {
final int index = i;
ListenableFuture<Foo> current = previous.transformAsync(
unused -> getFoo(index),
directExecutor());
results.add(current);
previous = current;
}
return allAsList(results);
},
directExecutor());
我对 Futures 还很陌生,一直坚持链接调用和创建对象列表。我正在使用 Android,API 最小值是 19。
我想对下面的方法 getAllFoo()
进行编码:
ListenableFuture<List<Foo>> getAllFoo() {
// ...
}
我有这两种方法可用:
ListenableFuture<Foo> getFoo(int index) {
// gets a Foo by its index
}
ListenableFuture<Integer> getNbFoo() {
// gets the total number of Foo objects
}
方法 Futures.allAsList()
在这里可以很好地工作,但我的主要限制是每次调用 getFoo(int index)
只能在前一个完成之前发生。
据我了解(并测试过),Futures.allAsList()
"fans-out" 呼叫(所有呼叫同时开始),所以 我不能使用类似的东西:
ListenableFuture<List<Foo>> getAllFoo() {
// ...
List<ListenableFuture<Foo>> allFutureFoos = new ArrayList<>();
for (int i = 0; i < size; i++) {
allFutureFoos.add(getFoo(i));
}
ListenableFuture<List<Foo>> allFoos = Futures.allAsList(allFutureFoos);
return allFoos;
}
我有这种(丑陋的)解决方案(有效):
// ...
final SettableFuture<List<Foo>> future = SettableFuture.create();
List<Foo> listFoos = new ArrayList<>();
addApToList(future, 0, nbFoo, listFoos);
// ...
private ListenableFuture<List<Foo>> addFooToList(SettableFuture future, int idx, int size, List<Foo> allFoos) {
Futures.addCallback(getFoo(idx), new FutureCallback<Foo>() {
@Override
public void onSuccess(Foo foo) {
allFoos.add(foo);
if ((idx + 1) < size) {
addFooToList(future, idx + 1, size, allFoos);
} else {
future.set(allFoos);
}
}
@Override
public void onFailure(Throwable throwable) {
future.setException(throwable);
}
});
return future;
}
如何使用 ListenableFuture
优雅地实现它?
我找到了多个相关主题(如 this or that),但这些主题使用的是 "coded" 转换,而不是基于可变数量的转换。
如何组合 ListenableFutures
并获得与 Futures.allAsList()
相同的 return 值,但通过链接调用(扇入)?
谢谢!
作为一般规则,与手动 addListener
/ 相比,将衍生期货与 transform
/catching
/whennAllSucceed
/whenAllComplete
链接在一起更好addCallback
来电。转换方法可以为您做更多的事情:
- 减少忘记设置输出从而挂起程序的机会
- 传播取消
- 避免保留内存的时间超过需要的时间
- 采取一些技巧来减少堆栈溢出的机会
无论如何,我不确定是否有一种特别优雅的方法可以做到这一点,但我建议按照以下思路(未经测试!):
ListenableFuture<Integer> countFuture = getNbFoo();
return countFuture.transformAsync(
count -> {
List<ListenableFuture<Foo>> results = new ArrayList<>();
ListenableFuture<?> previous = countFuture;
for (int i = 0; i < count; i++) {
final int index = i;
ListenableFuture<Foo> current = previous.transformAsync(
unused -> getFoo(index),
directExecutor());
results.add(current);
previous = current;
}
return allAsList(results);
},
directExecutor());