问题 异步弹簧控制器与普通控制器


我想通过在普通控制器上启用Spring Boot中的异步控制器来分析我可能看到的改进

所以这是我的测试代码。一个API返回Callable,另一个API是普通控制器API。这两个API都阻止了 10secs 模拟长时间运行的任务

@RequestMapping(value="/api/1",method=RequestMethod.GET)
    public List<String> questions() throws InterruptedException{
        Thread.sleep(10000);
        return Arrays.asList("Question1","Question2");
    }

    @RequestMapping(value="/api/2",method=RequestMethod.GET)
    public Callable<List<String>> questionsAsync(){
        return () -> {
            Thread.sleep(10000);
            return Arrays.asList("Question2","Question2");
        };
    }

我用这个配置设置嵌入式tomcat,即只有一个tomcat处理线程:

server.tomcat.max-threads=1
logging.level.org.springframework=debug

对/ api / 1的期望 由于只有一个tomcat线程,因此在10secs之后处理此请求将不会被接受

结果: 达到预期


对/ api / 2的期望 由于我们立即返回一个可调用的,所以单个tomcat线程可以自由处理另一个请求。 Callable将在内部启动一个新线程。因此,如果您点击相同的API,它也应该被接受。

结果: 这不会发生,直到可调用完全执行,不再接受进一步的请求。

为什么/ api / 2表现不如预期?


13080
2018-06-18 14:25


起源

Tomcat正在运行一个线程池,你得到了错误的期望。 - Roman C
@RomanC我提到过,我设置tomcat的线程池只包含1个线程。 - hellojava
只是为了确定:当春天线程正在睡觉时,你提交了哪种“其他请求”? - JB Nizet
你没有实际说出你是如何测试你的断言的。它对我来说是预期的(如果我有4个并发使用者,我看到使用异步控制器的吞吐量大约是4倍)。我使用与服务器不同的机器上运行的Apache工作台来测量它。 - Dave Syer
@DaveSyer谢谢。我用curl测试,我可以看到/ api / 2表现得如预期的那样。如下所述,它实际上是chrome浏览器的一个问题 - hellojava


答案:


@DaveSyer是对的,/ api / 2实际上是按预期运行的。

我假设您正在使用Web浏览器测试该行为。至少Firefox和Chrome会阻止对同一网址的多个同时请求。如果您使用api / 2打开2个选项卡,则第二个选项卡将仅在第一个获得响应后向应用程序发送请求。

尝试使用简单的bash脚本进行测试,例如:

curl localhost/api/2 &
curl localhost/api/2 &
curl localhost/api/2 &

它将在同一时间打印3个响应。


13
2018-06-19 23:49



你和@DaveSyer是绝对正确的!此问题仅在浏览器中发生,而不是使用curl或任何http客户端测试工具。 - hellojava