gpt4 book ai didi

java - 避免等待 Servlet 流

转载 作者:IT老高 更新时间:2023-10-28 21:01:18 25 4
gpt4 key购买 nike

我的 Servler 花费了相当长的时间来读取 request.getInputStream() 并写入 response.getOutputStream()。从长远来看,这可能是一个问题,因为它阻塞线程只是为了每秒读取/写入 literally 几个字节。 (*)

我对部分请求数据从不感兴趣,在请求完全可用之前不应开始处理。响应也是如此。

我想,异步 IO 会解决它,但我想知道什么是正确的方法。也许一个 servlet Filter 用一个包装的 ByteArrayInputStream 替换 ServletInputStream,使用 request.startAsync 并在之后调用链式 servlet收集了全部输入?

  • 已经有这样的过滤器了吗?
  • 我应该写一个还是应该使用不同的方法?

请注意,我的意思是避免在缓慢的 servlet 流上浪费线程。这与 startAsync 不同,后者可以避免浪费线程等待某个事件

是的,目前这是一个过早的优化。

按要求我的读取循环

我目前的输入流读取方法没有什么有趣的,但是你在这里:

private byte[] getInputBytes() throws IOException {
ServletInputStream inputStream = request.getInputStream();
final int len = request.getContentLength();
if (len >= 0) {
final byte[] result = new byte[len];
ByteStreams.readFully(inputStream, result);
return result;
} else {
return ByteStreams.toByteArray(inputStream);
}
}

仅此而已,当数据不可用时它会阻塞; ByteStreams 来自 Guava。

到目前为止我的理解总结

正如答案明确指出的那样,在不浪费线程的情况下使用 servlet 流是不可能的。 servlet 架构和通用实现都没有公开任何允许说“缓冲整个数据并仅在您收集所有内容时才给我打电话”的东西,尽管他们使用 NIO 并且可以做到。

原因可能是通常使用像 nginx 这样的反向代理,它可以做到。 nginx 默认做这个缓冲,直到 two years ago 才关闭。 .

居然支持案例???

鉴于很多否定的答案,我不确定,但这看起来像是我的目标

to avoid wasting threads on slow servlet streams

实际上是完全支持:从 3.1 开始,有 ServletInputStream.html#setReadListener这似乎正是为此而生的。分配用于处理 Servlet#Service 的线程最初调用 request.startAsync(),附加监听器并通过简单地从 service 返回返回到池中>。监听器实现onDataAvailable(),当可以读取不阻塞时调用它,添加一条数据并返回。在onAllDataRead()中,我可以对采集到的数据进行整体处理。

有一个 example ,如何使用 Jetty 来完成。它似乎也涵盖了非阻塞输出。


(*) 在日志文件中,我可以看到读取输入(100 字节 header + 100 字节数据)的请求最多需要 8 秒。这种情况很少见,但确实会发生,尽管服务器大多处于空闲状态。所以我猜,这是一个连接非常糟糕的移动客户端(我们的一些用户从连接如此糟糕的地方连接)。

最佳答案

HttpServletRequest#startAsync()对此没有用。这仅对推送诸如 Web 套接字和良好的 'ol SSE 之类的东西有用。此外,JSR356 Web Socket API 是建立在它之上的。

您的具体问题已了解,但这绝对不能从 servlet 开始解决。由于非常简单的原因,您最终只会浪费更多线程,因为容器已经将当前线程专用于 servlet 请求,直到请求正文被完全读取到最后一位,即使它最终被新生成的读取异步线程。

为了节省线程,您实际上需要一个支持 NIO 的 servletcontainer,并在必要时打开该功能。使用 NIO,单个线程可以处理可用堆内存允许的尽可能多的 TCP 连接,而不是为每个 TCP 连接分配单个线程。然后,在您的 servlet 中,您根本不需要担心这个微妙的 I/O 任务。

几乎所有现代 servlet 容器都支持它:Undertow (野蝇), Grizzly (GlassFish/Payara), Tomcat , Jetty等。有些默认启用,有些则需要额外配置。只需使用关键字“NIO”引用他们的文档即可。

如果您实际上还想保存 servlet 请求线程本身,那么您基本上需要退后一步,删除 servlet 并在现有 NIO 连接器(Undertow、Grizzly 、 jetty 等)。

关于java - 避免等待 Servlet 流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44947813/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com