java 如何在 vert.x 中阻止线程等待响应?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37206327/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 02:17:35  来源:igfitidea点击:

How to block thread to wait for response in vert.x?

javareactive-programmingvert.xevent-driven

提问by tausif

I have a situation where I call an external API A and use its response to feed to request of API B and call it and afterwards return the response to caller of API A. Something like below

我有一种情况,我调用外部 API A 并使用它的响应来提供 API B 的请求,然后调用它,然后将响应返回给 API A 的调用者。如下所示

   method(){
    response = call API A
    }

    method_for_API_A(){
      handler() ->{
      API_B
      }
    return response;
    }

    method_for_API_B(){
    //code to call API B
    }

What I am facing here is that API A method is returning response without waiting for getting response from B.

我在这里面临的是 API A 方法正在返回响应,而无需等待从 B 获得响应。

I checked about executeBlocking method of vert.x and also tried of using 'blocking queue' but unable to achieve what I am intended to do. Can someone please direct me to correct way of doing it.Thanks in advance.

我检查了 vert.x 的 executeBlocking 方法,并尝试使用“阻塞队列”但无法实现我的意图。有人可以指导我正确的做法吗?提前致谢。

EDIT: Just to explain the exact scenario

编辑:只是为了解释确切的场景

Class MyClass{
 public Response method_A (Request request){
 String respFromApiA = Call_API_A(request) ;  // STEP 1
 Response respFromApiB = Call_API_B(request, respFromApiA); // STEP 2
 Print(respFromApiB)   // PRINT FINAL Response
 return respFromApiB; // STEP 3
}

String Call_API_A(Request request){
// Implementation
Print(string);  // PRINT API A response
return string
}

Response Call_API_B(Response response){
// Implementation
Print(response);  // PRINT API B response
return response;
}

}

I am using vert.x framework with Java. Now what happens during execution is, flow comes to STEP 1, initiate API A call. Goes to STEP 2 (without waiting for 'respFromApiA') and makes call to API B (which fails eventually because respFromApiA is NULL). And finally flow goes to STEP 3 and return from here. (without waiting for outcomes of API A and API B). If we see the print order it will be something like this

我在 Java 中使用 vert.x 框架。现在执行过程中发生的事情是,流程来到第 1 步,发起 API A 调用。转到第 2 步(不等待 'respFromApiA')并调用 API B(最终失败,因为 respFromApiA 为 NULL)。最后流程转到第 3 步并从这里返回。(无需等待 API A 和 API B 的结果)。如果我们看到打印顺序,它将是这样的

PRINT FINAL Response
PRINT API A response
PRINT API B response

What I am trying to achieve?

我正在努力实现什么?

Wait for API A response.
Make call to API B. Wait for API B response.
Return response got from API B.

I hope I am able to make clear this time. Please let me know if you need further inputs.

我希望这次我能说清楚。如果您需要进一步的输入,请告诉我。

回答by alexvetter

Vert.x is highly asynchronous. Most operations will in fact return immediately but their results will be available to a Handlerat a later point in time. So far so good. If I understand you correctly than you need to call Bin the Handlerof A. In this case Aneeds to be finished and the result would be available before you call B:

Vert.x 是高度异步的。大多数操作实际上会立即返回,但它们的结果将Handler在稍后的时间点提供给 a 。到现在为止还挺好。如果我理解正确,你比你需要调用BHandlerA。在这种情况下A需要完成并且结果将在您调用之前可用B

callA(asyncResultA -> {
  System.out.println("Result A: " + asyncResultA.result());

  callB(asyncResultB -> {
    System.out.println("Result B:" + asyncResultB.result());
  });
});

But what you are trying is to make something asynchronous synchron. You can not and should not try to make a asynchronous result available in the main program flow — that wouldn't work.

但是您正在尝试进行异步同步。您不能也不应该尝试在主程序流中提供异步结果——那是行不通的。

String respFromApiA = Call_API_A(request); // STEP 1
Response respFromApiB = Call_API_B(request, respFromApiA); // STEP 2
Print(respFromApiB); // PRINT FINAL Response
return respFromApiB; // STEP 3

Call_API_Acan't really return a result because it's calculated asynchronously. The result is only available for the Handlerof Call_API_A(see my example above). Same for Call_API_B– so you can't return the result of Call_API_B. The caller of your class would also need to call your class with a Handler.

Call_API_A无法真正返回结果,因为它是异步计算的。结果仅适用于Handlerof Call_API_A(参见我上面的示例)。相同Call_API_B- 所以你不能返回Call_API_B. 您班级的调用者还需要使用Handler.

Now some additional information. In your case you have the problem that multiple asynchronous results depend on each other. Vert.x provides a much more convenient way to handle asynchronous results — the so called Futures. A Future(sometimes called Promisebut in the Java world they are called Future) is a placeholder for results of asynchronous calls. Read about them in the documentation.

现在提供一些附加信息。在您的情况下,您遇到多个异步结果相互依赖的问题。Vert.x 提供了一种更方便的方式来处理异步结果——所谓的Futures. A Future(有时称为,Promise但在 Java 世界中称为Future)是异步调用结果的占位符。在文档中阅读有关它们的信息

With a Futureyou can do something like this:

使用 aFuture你可以做这样的事情:

Future<...> callAFuture = Future.future();
callA(asyncResultA -> {
  if (asyncResultA.succeeded()) {
    System.out.println("A finished!");
    callAFuture.complete(asyncResultA.result());
  } else {
    callAFuture.fail(asyncResultA.cause());
  }
});

So instead of trying to return the asynchronous result of Bin a synchronous way you should return a Futureso the callee of your class could register for the asynchronous result of both Aand B.

因此,而不是试图返回异步结果B以同步的方式,你应该返回Future,以便类的被叫方可以为双方的异步结果寄存器AB

I hope this helps.

我希望这有帮助。

Edit: Future as return value

编辑:未来作为返回值

Lets say you want to wrap callAwith so you can work with a Future. You could do it this way:

假设您想要包装callA,以便您可以使用Future. 你可以这样做:

public Future<String> doSomethingAsync() {
  Future<String> callAFuture = Future.future();

  // do the async stuff
  callA(asyncResultA -> {
    if (asyncResultA.succeeded()) {
      System.out.println("A finished!");
      callAFuture.complete(asyncResultA.result());
    } else {
      callAFuture.fail(asyncResultA.cause());
    }
  });

  // return Future with the asyncResult of callA
  return callAFuture;
}

The Caller of this function can use the Future like this:

这个函数的调用者可以像这样使用 Future:

Future<String> doSomethingFuture = doSomethingAsync();
doSomethingFuture.setHandler(somethingResult -> {
  // ... doSomethingAsync finished
});

It also possible to compose multiple Futureif you want to do them concurrently but they don't dependent on each other:

Future如果您想同时执行它们,但它们不相互依赖,也可以组合多个:

CompositeFuture.all(futureA, futureB).setHandler(connections -> {
  // both Futures completed
});

If you work in a asynchronous environment like Vert.x most of time you work with a soon-to-be-available-resultaka Future. And in the Handlerof a Futureyou often do another asynchronous call. You wrap a Futurewith a Futurelike the example of callBin callA's Handler.

如果你在像 Vert.x 这样的异步环境中工作,大部分时间你都会使用一个即将可用的结果aka Future。而在Handlera 中,Future您经常会进行另一个异步调用。你一包FutureFuture类似的例子callBcallAHandler

How would you return the asynchronous result of a Futureas an HTTP Response? Like this:

您将如何将 a 的异步结果Future作为 HTTP 响应返回?像这样:

router.route("/").handler(routingContext -> {
  HttpServerResponse response = routingContext.response();

  Future<String> future = doSomethingAsync();
  future.setHandler(somethingResult -> {
    if (somethingResult.succeeded()) {
      response
        .end(somethingResult.result());
    } else {
      routingContext.fail(500);
    }
  });
});

回答by OLH

I have used Futureto return some resultsto use it again in other methodes, this is my implementation i hope it helps someone :

我曾经Future返回一些 results以在其他方法中再次使用它,这是我的实现,我希望它可以帮助某人:

 public static void ussdMessages(RoutingContext routingContext){
    String codeService = routingContext.getBodyAsJson().getString("codeService");
    Future<String> futureQuery=getServiceQuery(codeService);
    Future<JsonObject> futureParams = getServiceParams(codeService);
    CompositeFuture.all(futureQuery,futureParams).setHandler(r->{
        System.out.println(futureQuery.result());
        System.out.println(futureParams.result());
    });

}

public static Future<JsonObject> getServiceParams(String codeService){
    Future<JsonObject> future=Future.future();
    JsonObject params = new JsonObject();
    params.put("QUERY", Queries.DB_SELECT_SERVICE_PARAMS);
    params.put("PARAMS", new JsonArray().add(codeService));
    DB.select(params, res -> {
        if (res.succeeded()) {
            future.complete(res.result());
        } else {
            future.fail(res.cause().getMessage());
        }
    });
    return future;
}


public  static Future<String>  getServiceQuery(String codeService){
    Future<String> future = Future.future();
    JsonObject params = new JsonObject();
    params.put("QUERY", Queries.DB_SELECT_SERVICE_QUERY);
    params.put("PARAMS", new JsonArray().add(codeService));
    System.out.println(params);
    DB.select(params, res -> {
        if (res.succeeded()) {
          // query = res.result().getJsonArray("results").getJsonArray(0).getString(0);
            future.complete(res.result().getJsonArray("results").getJsonArray(0).getString(0));
        } else {
            future.fail(res.cause().getMessage());
        }
    });
    return future;
}

回答by Martin Gottweis

You have three options:

您有三个选择:

  1. Do the API A call and in the callback do the API B call.
  2. Use async framework(https://spring.io/guides/gs/async-method/) of your choice that will run both api calls in parallel.
  3. Same as first, but with promises.
  1. 执行 API A 调用,并在回调中执行 API B 调用。
  2. 使用您选择的异步框架(https://spring.io/guides/gs/async-method/),它将并行运行两个 api 调用。
  3. 与第一个相同,但有承诺。

Second is the best solution, since it will be considerably faster and you could add API C with little effort

第二个是最好的解决方案,因为它会快得多,而且你可以毫不费力地添加 API C