【问题标题】:Play framework, promises, non blocking thread programmingPlay框架、Promise、非阻塞线程编程
【发布时间】:2015-05-04 02:49:41
【问题描述】:

function1() 比 function2() 有什么好处(执行两个 GET 查询时的并行性很小)?在我看来,控制器线程在这两种情况下都是非阻塞的,但是在等待结果时必须阻塞其中一个后台线程。举个更好的例子,当我们查看 function3() 时,我们看到 databaseDao 线程被阻塞直到操作完成(使用内部 dao JPA)。

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);
}

如果函数阻塞我们的后台线程池很快就会消失。那么非盈利性的游戏框架和承诺优于 Spring 框架和 tomcat?

编辑:

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)));
}

上面的函数阻塞了两个线程,所以比function1还差?但是执行时间可以比较。比如promise1用5秒,promise2用4秒,结果会在5秒后出来?

【问题讨论】:

  • 在你的第一个例子中,如果 twitter req.需要 5 秒和类型安全的请求。需要 4 秒,您将在 5 秒内得到结果。在第二个函数中需要 9 秒。另外我知道 JDBC 是阻塞的,所以不管你使用的是 Play、Spring 还是???,它都会在某个地方阻塞

标签: java playframework promise nonblocking


【解决方案1】:

function1() 比 function2() 有什么好处(执行两个 GET 查询时的并行性很小)?

这不仅仅是并行性。 Play WS 基于 AsyncHttpClient 构建,它是一个非阻塞 API。在function2 中,您似乎正在使用Apache HttpClient,这是一个阻塞API。并行性有帮助。正如@Salem 已经说过的那样,function1 只会与最长的请求一样长,而 function2 每次都会与这两个请求一样长。

在我看来,控制器线程在这两种情况下都是非阻塞的,...

没错,只要 Promise 被转移到另一个 ExecutionContext,我们就不会阻止 Play 的内部结构。

...但是等待结果时必须阻塞其中一个后台线程。

不正确。由于function1 只调用异步的WS API,它不会阻塞等待响应的任何 线程。 function2 可能不会阻塞负责控制器功能的线程,但它必须阻塞某处。这并不是说将其包装在 Promise 中是一个坏主意——如果它必须阻止,它还不如在其他地方这样做。

...查看function3()我们看到databaseDao线程被阻塞直到操作完成(使用内部dao JPA)。

确实,大多数数据库驱动程序都会阻塞,除了尝试不太流行的异步驱动程序之外,没有其他方法可以解决这个问题。 function2function3 在行为上比 function1function2 更相似。 function 确实属于它自己的一类。

如果函数阻塞,我们的后台线程池很快就会消失。

是的,但大多数时候我们必须在某个地方阻塞,如果您可以选择使用异步 API,那就太好了。例如,出于上述原因,我总是使用function1 而不是function2。但是对于数据库调用,我使用阻塞 API,因为在一个对数据库进行大量读取的应用程序中,如果我的数据库已经被查询超载,那么保存一些应用程序线程并不会真正帮助我。

上面的函数[function4]阻塞了两个线程,所以比function1还差?但是执行时间可以比较。比如promise1用5秒,promise2用4秒,结果会在5秒后出来?

function4 更糟糕的是它比function1 做了更多的阻塞。这是否会立即影响您的应用程序的性能取决于您是否遇到了线程数。但我看不出有任何理由选择function4 而不是function1function4 可以在与 function1 相当的时间内完成,如果它有必要的线程来完成。如果池中只有一个线程可用,那么第二个 promise 可能必须等待第一个线程完成才能执行。在function1 中,这不会发生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 2016-07-14
    相关资源
    最近更新 更多