【问题标题】:Vert.x: How to wait for a future to completeVert.x:如何等待未来完成
【发布时间】:2019-04-20 22:09:39
【问题描述】:

有没有办法在不阻塞事件循环的情况下等待未来完成?

查询 Mongo 的用例示例:

Future<Result> dbFut = Future.future();
mongo.findOne("myusers", myQuery, new JsonObject(), res -> {
    if(res.succeeded()) {
      ...
      dbFut.complete(res.result());
    }
    else {
      ...
      dbFut.fail(res.cause());
    }
  }
  });

// Here I need the result of the DB query
if(dbFut.succeeded()) {
  doSomethingWith(dbFut.result());
}
else {
  error();
}

我知道doSomethingWith(dbFut.result()); 可以移动到处理程序,但如果它很长,代码将变得不可读(回调地狱?)这是正确的解决方案吗?这是没有额外库的万能解决方案吗?

我知道 rxJava 简化了代码,但我不知道,学习 Vert.x rxJava 实在是太多了。

我也想试试vertx-sync。我将依赖项放在pom.xml;一切都下载好了,但是当我启动我的应用程序时,出现以下错误

maurice@mickey> java \
  -javaagent:~/.m2/repository/co/paralleluniverse/quasar-core/0.7.5/quasar-core-0.7.5-jdk8.jar \
  -jar target/app-dev-0.1-fat.jar \
  -conf conf/config.json 
Error opening zip file or JAR manifest missing : ~/.m2/repository/co/paralleluniverse/quasar-core/0.7.5/quasar-core-0.7.5-jdk8.jar
Error occurred during initialization of VM
agent library failed to init: instrument

我知道该错误的一般含义,但我不知道在那种情况下...我试图用谷歌搜索它,但没有找到任何关于将哪个清单放在哪里的明确解释。和以前一样,除非是强制性的,否则我更喜欢一次学习一件事。

那么,回到问题:“基本”Vert.x 有没有一种方法可以等待未来而不会干扰事件循环?

【问题讨论】:

    标签: vert.x


    【解决方案1】:

    您可以设置一个处理程序,以便将来在完成或失败时执行:

    Future<Result> dbFut = Future.future();
    mongo.findOne("myusers", myQuery, new JsonObject(), res -> {
        if(res.succeeded()) {
          ...
          dbFut.complete(res.result());
        }
        else {
          ...
          dbFut.fail(res.cause());
        }
      }
      });
    
    dbFut.setHandler(asyncResult -> {
        if(asyncResult.succeeded()) {
          // your logic here
        }
    });
    

    这是一种纯 Vert.x 方式,不会阻塞事件循环

    【讨论】:

    • 这是一个过时的解决方案
    • 嘿 Vyacheslav :),如果您认为这是一个过时的解决方案,请随时添加新答案。
    • 代替使用future.setHandler,你可以使用future.onSuccess(value -> {}).onFailure(failure->{});此外,我通常有辅助功能,例如完成或失败我拥有的未来:FutureUtil.completeOrFail(res.succeeded(), res.result(), res.cause());或 FutureUtil.completeOrFail(res.succeeded(), () -> res.result(), () -> res.cause());如果你只能访问 res.result() 如果它成功了。还要检查 Vertx 4 API,他们可能已经与这些 util 函数合作了。
    【解决方案2】:

    我同意您不应阻塞 Vertx 处理管道,但我对该规则有一个例外:启动。按照设计,我想在我的 HTTP 服务器初始化时阻止。

    此代码可能对您有所帮助:

    /**
     * @return null when waiting on {@code Future<Void>}
     */
    @Nullable
    public static <T>
    T awaitComplete(Future<T> f)
    throws Throwable
    {
        final Object lock = new Object();
        final AtomicReference<AsyncResult<T>> resultRef = new AtomicReference<>(null);
        synchronized (lock)
        {
            // We *must* be locked before registering a callback.
            // If result is ready, the callback is called immediately!
            f.onComplete(
                (AsyncResult<T> result) ->
                {
                    resultRef.set(result);
                    synchronized (lock) {
                        lock.notify();
                    }
                });
    
            do {
                // Nested sync on lock is fine.  If we get a spurious wake-up before resultRef is set, we need to
                // reacquire the lock, then wait again.
                // Ref: https://stackoverflow.com/a/249907/257299
                synchronized (lock)
                {
                    // @Blocking
                    lock.wait();
                }
            }
            while (null == resultRef.get());
        }
        final AsyncResult<T> result = resultRef.get();
        @Nullable
        final Throwable t = result.cause();
        if (null != t) {
            throw t;
        }
        @Nullable
        final T x = result.result();
        return x;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-01-07
      • 2014-11-11
      • 2019-10-08
      • 1970-01-01
      • 2016-04-20
      • 2021-03-17
      • 2020-10-11
      • 2020-08-05
      • 2020-07-05
      相关资源
      最近更新 更多