user2860204
user2860204

Reputation: 171

Play framework, promises, non blocking thread programming

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

Answers (1)

Michael Zajac
Michael Zajac

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

Related Questions