[英]Mutiny - How to group items to send request by blocks
我正在使用 Mutiny 擴展(用於 Quarkus),但我不知道如何解決這個問題。
我想以異步方式發送許多請求,所以我讀過 Mutiny 擴展。 但是服務器關閉了連接,因為它收到了數千個。
所以我需要:
我一直在使用 Uni object 將所有響應組合為:
Uni<Map<Integer, String>> uniAll = Uni.combine()
.all()
.unis(list)
.combinedWith(...);
接着:
uniAll.subscribe()
.with(...);
此代碼並行發送所有請求,以便服務器關閉連接。
我正在使用一組 Multi 對象,但我不知道如何使用它(在 Mutiny 文檔中我找不到任何示例)。
這就是我現在正在做的方式:
//Launch 1000 request
for (int i=0;i<1000;i++) {
multi = client.getAbs("https://api.*********.io/jokes/random")
.as(BodyCodec.jsonObject())
.send()
.onItem().transformToMulti(
array -> Multi.createFrom()
.item(array.body().getString("value")))
.group()
.intoLists()
.of(100)
.subscribe()
.with(a->{
System.out.println("Value: "+a);
});
}
我認為訂閱不會執行,直到有“100”組項目,但我想這不是方式,因為它不起作用。
有人知道如何在 100 個塊中啟動 1000 個異步請求嗎?
提前致謝。
2021 年 4 月 19 日更新
我試過這種方法:
List<Uni<String>> listOfUnis = new ArrayList<>();
for (int i=0;i<1000;i++) {
listOfUnis.add(client
.getAbs("https://api.*******.io/jokes/random")
.as(BodyCodec.jsonObject())
.send()
.onItem()
.transform(item -> item
.body()
.getString("value")));
}
Multi<Uni<String>> multiFormUnis = Multi.createFrom()
.iterable(listOfUnis);
List<String> listOfResponses = new ArrayList<>();
List<String> listOfValues = multiFormUnis.group()
.intoLists()
.of(100)
.onItem()
.transformToMultiAndConcatenate(listOfOneHundred ->
{
System.out.println("Size: "+listOfOneHundred.size());
for (int index=0;index<listOfOneHundred.size();index++) {
listOfResponses.add(listOfOneHundred.get(index)
.await()
.indefinitely());
}
return Multi.createFrom()
.iterable(listOfResponses);
})
.collectItems()
.asList()
.await()
.indefinitely();
for (String value : listOfValues) {
System.out.println(value);
}
當我把這條線:
listOfResponses.add(listOfOneHundred.get(index)
.await()
.indefinitely());
響應一個接一個地打印,當前 100 組項目結束時,它會打印下一組。 問題? 有順序請求,需要很多時間
我想我已經接近解決方案了,但我需要知道,如何僅以 100 組為一組發送並行請求,因為如果我輸入:
subscribe().with()
所有請求都是並行發送的(而不是 100 組)
我認為你創造了很多錯誤,使用它會更容易:
Multi<String> multiOfJokes = Multi.createFrom().emitter(multiEmitter -> {
for (int i=0;i<1000;i++) {
multiEmitter.emit(i);
}
multiEmitter.complete();
}).onItem().transformToUniAndMerge(index -> {
return Uni.createFrom().item("String" + index);
})
使用這種方法,它應該使調用並行。 現在是如何將其列入列表的問題。
分組工作正常,我使用以下代碼運行它:
Random random = new Random();
Multi<Integer> multiOfInteger = Multi.createFrom().emitter(multiEmitter -> {
for (Integer i=0;i<1000;i++) {
multiEmitter.emit(i);
}
multiEmitter.complete();
});
Multi<String> multiOfJokes = multiOfInteger.onItem().transformToUniAndMerge(index -> {
if (index % 10 == 0 ) {
Duration delay = Duration.ofMillis(random.nextInt(100) + 1);
return Uni.createFrom().item("String " + index + " delayed").onItem()
.delayIt().by(delay);
}
return Uni.createFrom().item("String" + index);
}).onCompletion().invoke(() -> System.out.println("Completed"));
Multi<List<String>> multiListJokes = multiOfJokes
.group().intoLists().of(100)
.onCompletion().invoke(() -> System.out.println("Completed"))
.onItem().invoke(strings -> System.out.println(strings));
multiListJokes.collect().asList().await().indefinitely();
您將獲得您的字符串列表。
我不知道,您打算如何將列表發送到后端。 但是您可以使用以下方法之一:
我希望你以后能更好地理解它。
PS:鏈接到我學到所有這些的指南: https://smallrye.io/smallrye-mutiny/guides
因此,簡而言之,您希望批量並行調用服務器,而不是一次性使用所有內容。
這對你有用嗎? 它使用merge
。 在我的示例中,它的並行度為 2。
Multi.createFrom().range(1, 10)
.onItem()
.transformToUni(integer -> {
return <<my long operation Uni>>
})
.merge(2) //this is the concurrency
.collect()
.asList();
我不確定今年晚些時候是否添加了merge
,但這似乎可以滿足您的要求。 在我的示例中,“長操作生成 Uni”實際上是對 Microprofile Rest 客戶端的調用,該客戶端生成 Uni,並返回一個字符串。 merge
后,您可以放置另一個onItem
來執行響應(在merge
之后是一個普通的Multi
),而不是將所有內容收集為列表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.