[英]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.