Reputation: 171
What profit is from function1() over function2() (except little parallelism when two GET query is executing)? In my opinion controller thread is non blocked in both cases, but one of background thread must be blocked when waiting for result. For better example when we look at function3() we see that databaseDao thread is blocked until operation is finished (inside dao JPA is used).
public static F.Promise<Result> function1() {
final F.Promise<WSResponse> twitterPromise = WS.url("http://www.twitter.com").get();
final F.Promise<WSResponse> typesafePromise = WS.url("http://www.typesafe.com").get();
return twitterPromise.flatMap((twitter) -> typesafePromise.map((typesafe) -> ok(twitter.getBody() + typesafe.getBody())));
}
public static F.Promise<Result> function2() {
F.Promise<String> promise = F.Promise.promise(() -> {
HttpClient client = HttpClientBuilder.create().build();
HttpGet request1 = new HttpGet("http://www.twitter.com");
HttpGet request2 = new HttpGet("http://www.typesafe.com");
HttpResponse response = client.execute(request1);
HttpResponse response2 = client.execute(request2);
// result is not important
return response.toString() + response2.toString();
});
return promise.map(Results::ok);
}
public static F.Promise<Result> function3() {
F.Promise<String> promise = F.Promise.promise(() -> databaseDao.longRunningOperation());
return promise.map(Results::ok);
}
If functions are blocking our background thread pool is gone fast. So non profit play framework and promises over Spring framework and tomcat?
EDIT:
public static F.Promise<Result> function4() {
F.Promise<String> promise = F.Promise.promise(() -> {
HttpClient client = HttpClientBuilder.create().build();
HttpGet request1 = new HttpGet("http://www.twitter.com");
HttpResponse response = client.execute(request1);
return response.toString();
});
F.Promise<String> promise2 = F.Promise.promise(() -> {
HttpClient client = HttpClientBuilder.create().build();
HttpGet request2 = new HttpGet("http://www.typesafe.com");
HttpResponse response2 = client.execute(request2);
return response2.toString();
});
return promise.flatMap(p1 -> promise2.map(p2 -> ok(p1 + p2)));
}
above function is blocking two threads, so it is worse than function1? But executing time can be comparable. For example if promise1 take 5second, and promise2 take 4 second, result will come in 5 second?
Upvotes: 3
Views: 1909
Reputation: 55569
What profit is from function1() over function2() (except little parallelism when two GET query is executing)?
It's more than parallelism. Play WS is built on of of AsyncHttpClient, which is a non-blocking API. In function2
it looks like you're using Apache HttpClient, which is a blocking API. The parallelism helps. As @Salem has already said, function1
will only as long as the longest request, whereas function2
will take as long as both requests, every time.
In my opinion controller thread is non blocked in both cases, ...
True, we won't block Play's internals so long as the Promise
is shuttled off to another ExecutionContext
.
...but one of background thread must be blocked when waiting for result.
Not true. Since function1
is making only calls to the WS API, which is asynchronous, it will not block any threads waiting for a response. function2
might not block threads responsible for controller functions, but it must block somewhere. That's not to say that wrapping it in a Promise
is a bad idea--if it has to block, it might as well do it elsewhere.
...look at function3() we see that databaseDao thread is blocked until operation is finished (inside dao JPA is used).
Indeed, most database drivers will block, and there isn't really any way of getting around that other than trying less popular asynchronous ones. function2
and function3
are more similar in behavior than function1
and function2
are. function
is really in a class of it's own.
If functions are blocking our background thread pool is gone fast.
Yes, but most of the time we have to block somewhere, and if you have the choice of using an asynchronous API, then great. For example, I would always use function1
over function2
for the reasons explained above. But with database calls I live with the blocking API, because in an application that's read-heavy on the database, saving a few application threads won't really help me if my database is already overloaded with queries.
above function [function4] is blocking two threads, so it is worse than function1? But executing time can be comparable. For example if promise1 take 5second, and promise2 take 4 second, result will come in 5 second?
function4
is worse in that it does a lot more blocking than function1
. Whether or not that affects the performance of your application immediately depends on whether you're bumping up against your thread count. But I don't see any reason to choose function4
over function1
ever. function4
can complete in a comparable amount of time as function1
, provided it has the requisite threads to do so. If there is only one thread available in the pool, then the second promise may have to wait for the first to complete before executing. In function1
, this wouldn't happen.
Upvotes: 2