Future Vert.x получает нулевое значение, потому что обработчик запускается до завершения будущего

Я пытаюсь понять структуру Vert.x, и у меня есть задача создать HTTP-сервер, который будет выполнять простые математические вычисления, и клиента, который будет отправлять несколько запросов на этот сервер. Мне нужно посчитать время, необходимое для отправки всех запросов и получения ответов. Мне удалось создать клиента, сервер и отправлять запросы и получать ответы, но у меня проблема с измерением времени, необходимого для выполнения этих операций.

Моя клиентская версия имеет следующий метод start():

@Override
    public void start() throws Exception {

        WebClient client = WebClient.create(vertx);

        IntStream.range(0, MathClientApp.REQUEST_NUMBER)
            .forEach(i -> Arrays.stream(Operations.values()).forEach(operation -> {

                client
                    .get(8080, "localhost", operation.getPath())
                    .addQueryParam("numbers", StringUtils.join(numbers, ","))
                    .send(result -> {
                        if (result.succeeded()) {
                            Double mathResult = Double.parseDouble(result.result().bodyAsString());
                            if (mathResult.equals(operation.result(numbers))) {
                                System.out.println("Result: " + result.result().bodyAsString() + " OK!");
                            } else {
                                System.out.println("Result: " + result.result().bodyAsString() + " WRONG!");
                            }
                        } else {
                            System.out.println("Communication failed.");
                        }
                    });
            }));
    }

Operations - это перечисление со всеми математическими операциями, которые может выполнять сервер.

Теперь я понял, что мне нужно установить время начала перед отправкой запроса клиенту, а затем установить время окончания для обратного вызова send(). Поскольку операции являются асинхронными, время окончания не может быть установлено в момент получения его для подсчета разницы, поэтому я подумал, что это время окончания должно быть объектом Future. Итак, я добавил код:

@Override
    public void start() throws Exception {

        WebClient client = WebClient.create(vertx);

        IntStream.range(0, MathClientApp.REQUEST_NUMBER)
            .forEach(i -> Arrays.stream(Operations.values()).forEach(operation -> {

                Long startTime = System.currentTimeMillis();
                Future<Long> endTime = Future.future(future -> {
                    times.add(future.result() - startTime);
                });

                client
                    .get(8080, "localhost", operation.getPath())
                    .addQueryParam("numbers", StringUtils.join(numbers, ","))
                    .send(result -> {
                        if (result.succeeded()) {
                            endTime.complete(System.currentTimeMillis());
                            Double mathResult = Double.parseDouble(result.result().bodyAsString());
                            if (mathResult.equals(operation.result(numbers))) {
                                System.out.println("Result: " + result.result().bodyAsString() + " OK!");
                            } else {
                                System.out.println("Result: " + result.result().bodyAsString() + " WRONG!");
                            }
                        } else {
                            System.out.println("Communication failed.");
                        }
                    });
            }));
    }

Я понимаю следующее: перед каждым запросом я беру текущее время в миллисекундах и создаю Future для окончания времени с помощью обработчика, который вычитает это время, когда появится время окончания. Затем запрос отправляется, и когда получен ответ, устанавливается время окончания, поэтому вызывается метод обработчика Future, время вычитается и сохраняется в списке всех времен из всех запросов.

Но я получаю исключение NullPointerException в методе обработчика Future. Он выполняется перед вызовом сервера, поэтому значение еще не указано. Я не могу понять, почему, и в официальной документации по Vert.x не сказано, как именно использовать эту Future функцию.


person Mesayah    schedule 08.03.2018    source источник


Ответы (1)


Вы должны проверить, было ли выполнено future внутри метода-обработчика. Это будет выглядеть примерно так:

Future<Long> endTime = Future.future(future -> {
    if(future.succeeded()) {
        times.add(future.result() - startTime);
    }
});
person Guts    schedule 08.03.2018