嵌套期货是否是一种反模式?

huangapple go评论74阅读模式
英文:

Is nesting of futures an anti pattern?

问题

我有一个正在创建的ListenableFuture,如下所示:

ListenableFuture<X> future1 = ...
ListenableFuture<X> future2 = ...
Futures.addCallback(future1, futureCallback, executor);

现在在futureCallback内部我这样做:

public void onSuccess(Object result) {
  Object f2 = future2.get();
  .
  .
  . <对 f2 做一些操作>
}

在回调中进行.get()调用是一件不好的事情吗?有人告诉我这样可能会导致程序挂起。这是真的吗?为什么会发生这种情况?
有没有更好的方法来实现相同的功能?

英文:

I have a ListenableFuture that I am creating like:

ListenableFuture&lt;X&gt; future1 = ...
ListenableFuture&lt;X&gt; future2 = ...
Futures.addCallback(future1, futureCallback, executor);

Now inside the futureCallback I do :

public void onSuccess(Object result) {
  Object f2 = future2.get();
  .
  .
  . &lt;do something with f2&gt;
}

Is it a bad thing to do a .get() call in a callback? I was told that I could get into a hung up state. Is that true and why would it so happen?
What is the alternative of achieving the same thing in a better way?

答案1

得分: 1

你可能更希望使用类似这样的方式:

whenAllSucceed(future1, future2).run(...)

你传递给 runRunnable 仍然需要调用 future2.get。不过,whenAllComplete 在某些方面优于 addCallback 方法:

  • addCallback 方法可能需要一个线程在 future2.get 上阻塞,直到 future2 完成。(这至少会浪费一些资源。如果线程用尽,你的代码可能会挂起。或者你可能尝试创建新线程并耗尽内存。)使用 whenAllComplete,你的 Runnable 不会在两个输入 future 都完成之前运行,因此 future2.get 不会阻塞。

  • whenAllComplete 返回一个 Future。你可以使用它来检查错误。如果你取消它,它会同时取消两个输入 future。

另请注意,如果多个输入失败,whenAllSucceed 会记录日志。这并不总是理想的。如果你不想要这种日志记录,你可能更喜欢 whenAllComplete。(希望将来我们会提供关闭日志记录的方法。)

英文:

You probably want something more like:

whenAllSucceed(future1, future2).run(...)

The Runnable you pass to run will still have to call future2.get. Still, whenAllComplete has some advantages over the addCallback approach:

  • The addCallback approach may require a thread to block on future2.get until future2 is done. (This is at least a small waste of resources. If you run out of threads, your code may hang. Or you might try to create a new thread and run out of memory.) With whenAllComplete, your Runnable won't run until both input futures are done, so future2.get will not block.

  • whenAllComplete returns a Future. You can use this to check for errors. And if you cancel it, it will cancel both input futures.

Note also that whenAllSucceed will log if multiple inputs fail. This isn't always desirable. If you don't want the logging, you might prefer whenAllComplete. (Hopefully someday we will provide a way to turn off the logging.)

答案2

得分: 0

在回调函数中进行.get()调用是非常常见的做法 - 这通常是你大部分时间想要做的 - 但更标准的模式是使用 transform 或者 transformAsync,以传入一个直接接受结果的函数。

英文:

Doing a .get() call in a callback is outright usual -- it's what you want to do most of the time -- but a more standard pattern is to, instead, use transform or transformAsync to pass in a function that takes the result directly.

答案3

得分: 0

在回调中执行阻塞操作(例如,future.get)会破坏异步编程的思想,将异步程序转变为普通的多线程程序。因此,这确实是一种反模式。
然而,如果你确定不会阻塞,调用get()是可以的。
如果你想要一个等待两个异步结果的回调,你可以使用CompletableFuture:

CompletableFuture<X> future1 = ...
CompletableFuture<X> future2 = ...
CompletableFuture future3 = future1.thenCombineAsync(future2, futureCallback, executor);
英文:

Doing blocking operation in callback (e.g. future.get) destroys the idea of asynchronous programming, turning asynchronous program in ordinary multithreaded. So this is indeed an antipattern.
It's OK, however, to call get() if you are sure it would not block.
If you want a callback which waits for 2 asynchronous results, you can use CompletableFuture instead:

CompletableFuture&lt;X&gt; future1 = ...
CompletableFuture&lt;X&gt; future2 = ...
CompletableFuture future3 = future1.thenCombineAsync(future 2, futureCallback, executor);

huangapple
  • 本文由 发表于 2020年9月4日 13:28:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/63735330.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定