【问题标题】:In Futures.transform, what is the difference between using a Function and an AsyncFunction在 Futures.transform 中,使用 Function 和 AsyncFunction 有什么区别
【发布时间】:2014-07-25 19:43:29
【问题描述】:

我知道Function的apply方法同步返回一个对象,AsyncFunction的apply异步运行,返回一个Future。

你能举个例子说明什么时候更喜欢什么。

我看到的一个代码 sn-p 看起来像这样:

Futures.transform(someFuture, new AsyncFunction<A, B>() {
  public B apply(A a) {
    if (a != null) {
      return Futures.immediateFuture(a.getData())
    } else {
      return Futures.immediateFailedFuture(checkException(());
    }
  });
});

既然 AsyncFunction 里面的值是立即返回的,为什么这里需要 AsyncFunction 呢?或者这只是我遇到的一个坏例子?

【问题讨论】:

标签: java guava future concurrent.futures


【解决方案1】:

您发现的代码 sn-p 是一个不好的示例,因为它使用 AsyncFunction 来处理同步计算的内容。这是不必要的冗长。

使用标准的Function 代码会更简洁:

Futures.transform(someFuture, new Function<A, B>() {
  public B apply(A a) {
    if (a != null) {
      return a.getData();
    } else {
      throw checkException();
    }
  });
});

当将 A 转换为 B 的代码是异步的时,您应该使用 AsyncFunction。在您的示例中,代码可能一开始是异步的,后来被程序员更改为使用Futures.immediateFuture() / Futures.immediateFailedFuture(),他不费心用Function 替换AsyncFunction。或者他只是错过了重载的方法。

【讨论】:

  • 我错过了一些东西。您如何判断将 A 转换为 B 的代码是/应该是同步的?
  • 这取决于您如何将 A 转换为 B。如果将 A 转换为 B 需要一些异步 I/O 或 WS 调用,则您必须使用返回 Future 的 AsyncFunction。在给出的示例中,Futures.immediateFuture() / Futures.immediateFailedFuture() 的使用表示同步转换。请记住,我只是在谈论转换函数的同步性,因为“someFuture”的计算可能是异步的。
  • 我们不知道a.getData() 做了什么,所以我仍然不明白你为什么假设它是同步的。我认为Futures.immediateFuture 只是用来包装a.getData() 的结果,因为apply 方法需要返回一个ListenableFuturea.getData() 的结果必须在返回 ListenableFuture 之前计算。因此,Futures.immediateFuture 相对于 a.getData 是同步的,但 transform 调用相对于 AsyncFunction 是异步的,反之亦然。 (请注意,OP 的代码似乎无法编译。)
  • Futures.immediateFuture() 是一个阻塞调用。它创建了一个 Future,但在被调用的同一线程中,这就是我们知道示例是同步的。
  • 在同步 I/O 上阻塞的代码是不好的,即使它是在不同的线程中完成的。它仍然是一个无用阻塞的 JVM 线程。另外,除非你指定一个Executor,我相信AsyncFunction是在完成输入Future的线程中执行的,这可能是有问题的。
【解决方案2】:

由于 AsyncFunction 内部的值作为立即结果返回, 为什么这里需要 AsyncFunction?或者这只是我的一个坏例子 遇到过?

小心。那段代码正在生成一个匿名类的实例并将该实例传递给transform 方法。 transform 方法将使用 AsyncFunction 是一个单独的线程。 Future 返回链以从 AsyncFunction 检索结果并返回 Future 的结果。此代码仍涉及异步处理。

当您想要并且可以在执行其他操作时继续工作时使用异步处理。

【讨论】:

    【解决方案3】:

    你给出的代码 sn-p 是一个不好的例子,写它的人应该使用 Function。

    Futures.transform() 用于跟进一些异步过程。让我们将其称为“异步进程 1”的“ap1”。当 ap1 完成后,由 transform 链接的函数将执行。 现在,让我们讨论您可以使用 Futures.transform() 链接的 2 种类型的函数。

        // AsyncFunction() example:
        ListenableFuture<B> future2 = Futures.transform(future1, new AsyncFunction<A, B>() {
          public ListenableFuture<B> apply(A a) {
            if (a != null) {
              ListenableFuture<B> future3 = asyncCallToOtherService(a);
              return future3;
            }
            else {
              return Future.immediateFuture(null);
            }
          });
        });
    
        // more complex AsyncFunction() example:
        ListenableFuture<B> future2 = Futures.transform(future1, new AsyncFunction<A, B>() {
          public ListenableFuture<B> apply(A a) {
            if (a != null) {
              ListenableFuture<C> future3 = asyncCallToOtherService(a);
              return Futures.transform(future3, new Function<C, B>() {
                @Override
                public B apply(C c) {
                  B b = new B();
                  b.setResult(c.getStatus());
                  return b;
                }
              });
            }
            else {
              return Future.immediateFuture(null);
            }
          });
        });
    
        // Function() example:
        ListenableFuture<B> future2 = Futures.transform(future1, new Function<A, B>() {
          public B apply(A a) {
            if (a != null) {
              B b = new B();
              b.setResult(a.getStatus());
              return b;
            }
            else {
              return null;
            }
          });
        });
    
    1. 当 apply() 中的代码产生另一个异步进程 2 (AP2) 时,应使用 AsyncFunction()。这形成了一系列相互跟随的异步调用:AP1->AP2。
    2. 当从 AP1 转换结果不需要任何额外的异步过程时,应使用 Function()。相反,它所做的只是以同步方式将结果 Object1 转换为其他 Object2。
    3. AsyncFunction() 稍微重一些,会导致单独的线程,因此我们应该在不需要旋转 AP2 时使用 Function()。
    4. 可以根据需要将多个函数和 AsyncFunction 链接在一起,以形成完整的工作流程。示例“更复杂的 AsyncFunction() 示例”链接 A~>C->B 转换,其中 A~>C 是异步的。

    【讨论】:

      【解决方案4】:

      在这里使用 AsyncFunction 是有意义的。如果您想从 Function 中的 apply() 方法中抛出一些已检查的异常,它会抱怨它没有被处理。您不能将其从 apply() 中丢弃,因为它已被覆盖。所以如果你想抛出一些检查异常,AsyncFunction 应该是一个有效的解决方案。对于那些说给定示例不好并且给定函数示例的人,您可以尝试编译它吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-12
        • 1970-01-01
        • 1970-01-01
        • 2017-12-05
        • 2015-03-08
        • 2012-02-18
        • 2012-10-18
        • 1970-01-01
        相关资源
        最近更新 更多