【问题标题】:Undertow how to do Non-blocking IO?Undertow 如何做非阻塞 IO?
【发布时间】:2014-04-01 06:39:12
【问题描述】:

我正在使用 Undertow 创建一个简单的应用程序。

public class App {
    public static void main(String[] args) {
        Undertow server = Undertow.builder().addListener(8080, "localhost")
                .setHandler(new HttpHandler() {

                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        Thread.sleep(5000);
                        exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                        exchange.getResponseSender().send("Hello World");
                    }

                }).build();
        server.start();
    }
}

我在localhost:8080 上打开一个浏览器选项卡,然后打开第二个 标签也在localhost:8080

这次第一个标签会等待 5 秒,第二个会等待 10 秒

为什么会这样?

【问题讨论】:

    标签: java undertow


    【解决方案1】:

    HttpHandler 正在一个 I/O 线程中执行。如the documentation中所述:

    IO线程执行非阻塞任务,并且不应该执行阻塞操作,因为它们负责多个连接,所以当操作阻塞时,其他连接基本上会挂起。每个 CPU 内核一个 IO 线程是合理的默认值。

    request lifecycle docs 讨论如何将请求分派到工作线程:

    import io.undertow.Undertow;
    import io.undertow.server.*;
    import io.undertow.util.Headers;
    
    public class Under {
      public static void main(String[] args) {
        Undertow server = Undertow.builder()
            .addListener(8080, "localhost")
            .setHandler(new HttpHandler() {
              public void handleRequest(HttpServerExchange exchange)
                  throws Exception {
                if (exchange.isInIoThread()) {
                  exchange.dispatch(this);
                  return;
                }
                exchange.getResponseHeaders()
                        .put(Headers.CONTENT_TYPE, "text/plain");
                exchange.getResponseSender()
                        .send("Hello World");
              }
            })
            .build();
        server.start();
      }
    }
    

    我注意到您不一定会在每个请求中获得一个工作线程 - 当我在标头上设置断点时,我会为每个客户端获得大约一个线程。 Undertow 和底层 XNIO docs 都存在差距,所以我不确定意图是什么。

    【讨论】:

    • @McDowell Node.js 在异步通信方面有什么不同吗?
    【解决方案2】:

    最简单的做法是将处理程序包装在 BlockingHandler 中。

    import io.undertow.Undertow;
    import io.undertow.server.*;
    import io.undertow.server.handlers.BlockingHandler;
    import io.undertow.util.Headers;
    
    public class Under {
        public static void main(String[] args) {
            Undertow server = Undertow.builder()
                    .addHttpListener(8080, "localhost")
                    .setHandler(new BlockingHandler(new HttpHandler() {
                        public void handleRequest(HttpServerExchange exchange)
                                throws Exception {
                            exchange.getResponseHeaders()
                                    .put(Headers.CONTENT_TYPE, "text/plain");
                            exchange.getResponseSender()
                                    .send("Hello World");
                        }
                    })).build();
            server.start();
        }
    }
    

    【讨论】:

      【解决方案3】:

      Undertow 使用 NIO,这意味着单个线程处理所有请求。如果您想在请求处理程序中执行阻塞操作,则必须将此操作分派给工作线程。

      在您的示例中,您使线程进入睡眠状态,这意味着任何请求处理都被置于睡眠状态,因为该线程处理所有请求。

      但是,即使您将操作分派给工作线程并将其置于睡眠状态,您仍然会看到您提到的阻塞问题。这是因为您在同一浏览器的多个选项卡中打开了相同的 url。浏览器有自己的内部阻塞。如果您在不同的选项卡中打开相同的 url,第二个 url 将在第一个完成后开始请求。尝试您想亲自查看的任何网址。您很容易对这种浏览器行为感到困惑。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-18
        • 1970-01-01
        • 1970-01-01
        • 2015-09-22
        • 2010-11-17
        • 2019-11-16
        • 1970-01-01
        相关资源
        最近更新 更多