问题描述
我想走一个异步函数的搜索空间。我将逻辑编码如下:
I want to walk the search space of an asynchronous function. I coded the logic as follows:
/**
* Assuming that a function maps a range of inputs to the same output value, minimizes the input value while
* maintaining the output value.
*
* @param previousInput the last input known to return {@code target}
* @param currentInput the new input value to evaluate
* @param function maps an input to an output value
* @param target the expected output value
* @return the minimum input value that results in the {@code target} output value
* <br>{@code @throws NullPointerException} if any argument is null
* <br>{@code @throws IllegalArgumentException} if {@code stepSize} is zero}
*/
private static CompletionStage<BigDecimal> optimizeInput(BigDecimal previousInput,
BigDecimal currentInput,
BigDecimal stepSize,
Function<BigDecimal, CompletionStage<BigDecimal>> function,
BigDecimal target)
{
return function.apply(currentInput).thenCompose(output ->
{
assertThat("stepSize", stepSize).isNotZero();
int outputMinusTarget = output.compareTo(target);
if (outputMinusTarget != 0)
return CompletableFuture.completedFuture(previousInput);
BigDecimal nextInput = currentInput.add(stepSize);
if (nextInput.compareTo(BigDecimal.ZERO) < 0)
return CompletableFuture.completedFuture(previousInput);
return optimizeInput(currentInput, nextInput, stepSize, function, target);
});
}
不幸的是,如果函数有一个很大的搜索空间,这会引发一些StackoverflowError迭代。是否可以使用固定大小的堆栈迭代地遍历搜索空间?
Unfortunately, if the function has a large search space this raises a StackoverflowError after some iterations. Is it possible to walk the search space iteratively, with a fixed-size stack?
推荐答案
您有以下递归结构
CompletableFuture<T> compute(...) {
return asyncTask().thenCompose(t -> {
if (...)
return completedFuture(t);
} else {
return compute(...);
}
}
}
您可以重写它,避免在完成期间完成未来的组合及其堆栈使用。
You can rewrite it avoiding completable future composition and its stack usage during completion.
CompletableFuture<T> compute(...) {
CompletableFuture<T> result = new CompletableFuture<>();
computeHelper(result, ...);
return result;
}
void computeHelper(CompletableFuture<T> result, ...) {
asyncTask().thenAccept(t -> {
if (...) {
result.complete(t);
} else {
computeHelper(result, ...);
}
});
}
如果 asyncTask()
并非真正异步而只是使用当前线程,你必须用其中一个异步版本替换 thenAccept
来使用执行任务队列而不是线程堆栈。
if asyncTask()
is not really asynchronous and just use the current thread, you must replace thenAccept
with one of its asynchronous versions to use the executor task queue instead of the thread stack.
这篇关于如何在不冒StackOverflowError风险的情况下使用CompletableFuture?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!