簡體   English   中英

Mutiny - 如何分組項目以按塊發送請求

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM