2

How is Apache NIO HttpAsyncClient able to wait for a remote response without blocking any thread? Does it have a way to setup a callback with the OS (I doubt so?). Otherwise does it perform some sort of polling?

HLP
  • 2,142
  • 5
  • 19
  • 20

1 Answers1

1

EDIT - THIS ANSWER IS WRONG. PLEASE IGNORE AS IT IS INCORRECT.

You did not specify a version, so I can not point you to source code. But to answer your question, the way that Apache does it is by returning a Future<T>.

Take a look at this link -- https://hc.apache.org/httpcomponents-asyncclient-4.1.x/current/httpasyncclient/apidocs/org/apache/http/nio/client/HttpAsyncClient.html

Notice how the link says nio in the package. That stands for "non-blocking IO". And 9 times out of 10, that is done by doing some work with a new thread.

This operates almost exactly like a CompletableFuture<T> from your first question. Long story short, the library kicks off the process in a new thread (just like CompletableFuture<T>), stores that thread into the Future<T>, then allows you to use that Future<T> to manage that newly created thread containing your non-blocking task. By doing this, you get to decide exactly when and where the code blocks, potentially giving you the chance to make some significant performance optimizations.

To be more explicit, let's give a pseudocode example. Let's say I have a method attached to an endpoint. Whenever the endpoint is hit, the method is executed. The method takes in a single parameter --- userID. I then use that userID to perform 2 operations --- fetch the user's personal info, and fetch the user's suggested content. I need both pieces, and neither request needs to wait for the other to finish before starting. So, what I do is something like the following.

public StoreFrontPage visitStorePage(int userID)
{

    final Future<UserInfo> userInfoFuture                 = this.fetchUserInfo(userID);
    final Future<PageSuggestion> recommendedContentFuture = this.fetchRecommendedContent(userId);

    final UserInfo userInfo = userInfoFuture.get();
    final PageSuggestion recommendedContent = recommendedContentFuture.get();

    return new StoreFrontPage(userInfo, recommendedContent);

}

When I call this.fetchUserInfo(userID), my code creates a new thread, starts fetching user info on that new thread, but let's my main thread continue and kick off this.fetchRecommendedContent(userID) in the meantime. The 2 fetches are occurring in parallel.

However, I need both results in order to create my StoreFrontPage. So, when I decided that I cannot continue any further until I have the results from both fetches, I call Future::get on each of my fetches. What this method does is merge the new thread back into my original one. In short, it says "wait for that one thread you created to finish doing what it was doing, then output the result as a return value".

And to more explicitly answer your question, no, this tool does not require you to do anything involving callbacks or polling. All it does is give you a Future<T> and lets you decide when you need to block the thread to wait on that Future<T> to finish.

EDIT - THIS ANSWER IS WRONG. PLEASE IGNORE AS IT IS INCORRECT.

davidalayachew
  • 1,279
  • 1
  • 11
  • 22
  • 1
    I'm not sure if your assumption is right. If their code just moved the RPC call to a separate thread (who wait/blocks for the response) and return me the Future of that thread, then it lose all the benefit of non-blocking philosophy. We just moved the blocking call from my thread to their thread, but the computer is still required to keep one thread in IO mode for every on-going request, so we aren't anyhow more efficient. My understanding of non-blocking framework is that they are able to wait for IO **without** having a thread alive. – HLP Dec 09 '22 at 16:49
  • Ah, so Apache has done something clever. If you look here (https://github.com/apache/httpcomponents-client/blob/22e5a0be6b46ae00af525e3aa8363b4cd87e0146/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java#L62), you can see that they use an `Executor` that only accepts one thread. So you are correct. I will blank out my answer for right now. Maybe some point later, I will update it to have correct information. – davidalayachew Dec 09 '22 at 18:38
  • And here is documentation on the Executor -- https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor-- – davidalayachew Dec 09 '22 at 18:38
  • 1
    You should not deface your posts, you can actually delete this answer yourself instead. Ideally, also rollback the changes so that 10k users can still see the original and understand why you deleted it. – Didier L Dec 13 '22 at 01:02
  • @DidierL People can see deleted answers? I was under the assumption that the entire point of deleting was to prevent exactly that. In the meantime, I have reverted, but with a disclaimer above and below that the information is false – davidalayachew Dec 13 '22 at 02:48
  • 1
    @davidalayachew https://stackoverflow.com/help/deleted-questions – Didier L Dec 13 '22 at 10:04