[英]CompletableFuture injection from the inside
是否可以从内部在CompletableFuture
链中注入 CompletableFuture
?
我正在使用这样的功能:
public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
// ... Some processing here ...
if (somecondition failed)
return false; // Task failed!
return true; // OK
}).thenApplyAsync((Boolean result) -> {
if (!result) // check of previous stage fail
return false;
// ... Some processing here ...
if (!some condition satisfied) {
// This is where I want the injection to happen.
// This stage should be suspended and a new stage should be injected between this point and the next stage.
}
return true; // OK
}).thenApplyAsync((Boolean result) -> {
if (!result) // check of previous stage fail
return false;
// ... Some processing here ...
return true; // OK
});
// This is the result we have to wait for.
return future;
}
在注入点if (!some condition satisfied)
,我想运行一个查询(例如),该查询需要5秒钟执行并检索最后阶段所需的一些数据。 我不想阻塞线程5秒钟,例如,使查询在if
同步,我希望它异步运行,然后返回结果直接进入下一阶段。 我遇到的问题是该条件仅在链内是已知的。
有人对此有想法吗?
编辑
我将尝试澄清这个问题。 我本来有一条唯一的代码。 现在,我正在尝试优化代码,以便产生更少的线程。
关键是在注入点我想发出类似的消息(对不起, Cassandra代码片段的Datastax Java驱动程序 ):
ResultSetFuture rsFuture = session.executeAsync(query);
并注入未来进入连锁。 这将使调用线程“无需”执行其他操作,而不必坐下来等待结果。
我不知道是否可以比这更清楚,但是让我们跟随这个例子。
我在主线程中运行一个循环:
for (int i = 0; i < 1000; i++) {
getFutureOfMyLongRunningTask(i);
}
该循环仅存在于主线程上,但是对函数的每次调用都会在线程池P中 排队一个新任务。 现在假设P是大小为1的固定线程池。 这意味着P中仅存在一个线程,并且只能处理1个任务。 但是,主循环将使所有1000个任务入队。 然后,主循环将需要等待所有任务完成。
现在假设1000个任务中的第一个任务需要执行一个长数据库查询。 现在,我们有两个选择:
该查询在处理线程内部 (属于线程池P ) 同步执行。 这意味着我只是在if (!some condition satisfied)
块内发出查询,然后等待结果。 这有效地阻止了任务处理,因为线程池P没有空闲线程。 唯一一个忙于 IO 阻塞 。
该查询是在处理线程内部 异步执行的(属于线程池P ),这意味着我在if (!some condition satisfied)
块内发出查询,并立即返回一个我将要收听的未来(可能是DB驱动程序)将产生另一个线程并阻止该线程等待结果)。 但是,属于P的线程现在可以自由处理至少另一个任务。
在我看来,选项2优于选项1 ,并且相同的推理可以应用于大小> 1或动态大小的线程池。
我想要的是保持线程池尽可能的空闲,以产生最少数量的线程,以避免浪费资源。
希望有道理。 如果没有,请您能解释我错了吗?
代替使用thenApplyAsync
,可以使用thenCompose
或thenComposeAsync
,它们使函数返回CompletableFuture<Foo>
而不是Foo
。 如果需要满足some condition
则需要return CompletableFuture.completedFuture(true)
,而不是return true
。
public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
// ... Some processing here ...
if (somecondition failed)
return false; // Task failed!
return true; // OK
}).thenComposeAsync((Boolean result) -> {
if (!result) // check of previous stage fail
return CompletableFuture.completedFuture(false);
// ... Some processing here ...
if (!some condition satisfied) {
return runSomeOtherQuery()
}
return CompletableFuture.completedFuture(true); // OK
}).thenApplyAsync((Boolean result) -> {
if (!result) // check of previous stage fail
return false;
// ... Some processing here ...
return true; // OK
});
// This is the result we have to wait for.
return future;
}
public CompletableFuture<Boolean> runSomeOtherQuery() {
....
}
似乎您正在考虑在链式阶段之间进行工作拆分(涉及“异步”)以某种方式神奇地为您的程序逻辑增加了并发性。
链接阶段时,即使使用“异步”方法之一,也将创建直接的顺序依赖关系,因为后续的依赖阶段的执行不会在前一个依赖阶段完成之前开始。 因此,这种链接增加了昂贵的线程跳跃的机会,即,另一个线程执行下一阶段,但又不提高并发性,因为最多会有一个线程处理您的一个阶段。 实际上,同一线程恰好执行所有阶段的可能性仍然是最快的。
有一种表达依赖关系的简单得多的自然方法。 只需在一段代码中一个接一个地编写动作。 您仍然可以安排该代码块进行异步执行。 因此,如果您的出发点是
public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
// First stage processing here ...
if (somecondition failed)
return false; // Task failed!
return true; // OK
}).thenApplyAsync((Boolean result) -> {
if (!result) // check of previous stage fail
return false;
// Second stage processing here ...
if (!some condition satisfied) {
// This is where I want the injection to happen.
// This stage should be suspended and a new stage should be
// injected between this point and the next stage.
}
return true; // OK
}).thenApplyAsync((Boolean result) -> {
if (!result) // check of previous stage fail
return false;
// Third stage processing here ...
return true; // OK
});
// This is the result we have to wait for.
return future;
}
只需将其更改为
public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
// First stage processing here ...
if (somecondition failed)
return false; // Task failed!
// Second stage processing here ...
if (!some condition satisfied) {
// alternative "injected" stage processing
if(injected stage failed)
return false;
}
// Third stage processing here ...
return true; // OK
});
// This is the result we have to wait for.
return future;
}
更短更清晰。 您不必反复检查上一个阶段的成功。 您仍然具有相同的并发性,但是执行效率可能更高。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.