泽西服务器端异步API未按预期工作

时间:2014-03-16 07:29:54

标签: java rest asynchronous jersey

我刚刚阅读了jersey文档并试图通过使用异步服务器端api来比较我可以节省多少时间,但我得到的结果令人困惑,请帮助发现我的代码中是否有错误。

这是资源类:

@Path("/async-sync")
public class CompareAsyncAndSyncResource {
    @GET
    @Path("sync-call")
    public String syncCall() throws InterruptedException {
        expensiveComputation();
        return "sync call finished";
    }

    @GET
    @Path("async-call")
    public void asyncCall(@Suspended final AsyncResponse asyncResponse) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                expensiveComputation();
                asyncResponse.resume("async call finished");
            }
        }).start();
    }

    private void expensiveComputation() {
        try {
            sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

一次同步来电和一次异步来电。

然后我做了这些测试:

public class CompareAsyncAndSyncResourceTest extends JerseyTest {
    @Override
    protected Application configure() {
        return new ResourceConfig().register(CompareAsyncAndSyncResource.class);
    }

    @Test
    public void sync_call_should_take_longer() throws Exception {
        final Stopwatch stopwatch = new Stopwatch();
        stopwatch.start();

        callFiveTimes(new Runnable() {
            @Override
            public void run() {
                String resp = target("async-sync/sync-call").request().get().readEntity(String.class);
                System.out.println("sync returned " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
                assertThat(resp, is("sync call finished"));
            }
        });

        stopwatch.stop();

        System.out.println("five clients calling sync get at same time " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    @Test
    public void async_call_should_take_shorter() throws Exception {
        final Stopwatch stopwatch = new Stopwatch();
        stopwatch.start();

        callFiveTimes(new Runnable() {
            @Override
            public void run() {
                String resp = target("async-sync/async-call").request().get().readEntity(String.class);
                System.out.println("async returned " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
                assertThat(resp, is("async call finished"));
            }
        });

        stopwatch.stop();

        System.out.println("five clients calling async get at same time " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    private void callFiveTimes(final Runnable runnable) throws InterruptedException {

        Iterable<Integer> rangeOfFive = newArrayList(1, 2, 3, 4, 5);
        FluentIterable<Thread> threads = from(rangeOfFive).transform(new Function<Integer, Thread>() {
            @Override
            public Thread apply(Integer number) {
                Thread thread = new Thread(runnable);
                thread.start();
                return thread;
            }
        });

        for (Thread thread : threads) {
            thread.join();
        }
    }
}

在测试中,我模拟了五个同时调用两个get调用的客户端,我想到完成五个异步调用会更快,但这是我得到的结果:

sync returned 1052
sync returned 2063
sync returned 3073
sync returned 4082
sync returned 5095
five clients calling sync get at same time 5096

同步部分是预期的,需要5秒才能完成,包括5个电话和一点开销。

但异步结果让我失望:

async returned 1847
async returned 2893
async returned 3904
async returned 4913
async returned 5923
five clients calling async get at same time 5923

看起来这五个异步调用并不是真正异步处理的。

我做错了什么?

PS:代码在这里:https://github.com/cuipengfei/jerseywhatnot/blob/master/src/main/java/com/jersey/whatnot/async/CompareAsyncAndSyncResource.java

编辑:我知道我现在做错了什么,它的番石榴,我应该调用toList。懒惰的评价再次让我感到高兴。但是看起来奇怪的是同步调用也变得更快,为什么呢?根据泽西的文档,同步获取调用应该阻止IO线程并减慢所有减少,但似乎没有发生。

1 个答案:

答案 0 :(得分:5)

这根本不是什么异步。

从根本上说,Java Servlet规范中的所有异步工具(Jersey利用)都允许您将传入请求与初始线程分开。

通常请求和处理线程绑定在一起。

促进这种分离本身并不会使任何事情变得更快。你用它做什么可以使它更快。

您的迷你基准测试连续5次调用服务器。同步版本放置原始请求线程上的处理,阻塞一秒钟,然后恢复。但是如果你考虑到这一点,你的服务器在任何时候都不会消耗多个活动的处理线程,因为你的所有调用都被序列化到服务器(即1,然后是2,然后是3 ......)。

您的异步调用接受请求,然后,它立即创建一个新线程,然后该线程完成处理,而不是直接服务它。在这种情况下,每个请求都会占用初始线程的一部分,然后继续使用第二个线程。但是,它必须分配和分配给新线程,而原始同步代码则不会。该调度需要时间,您的同步线程没有采取的时间,因此更慢&#34;。它变慢了,因为它只是在做更多的工作。 (服务器还在异步上下文中包含您的请求以及需要的内部簿记)。

async为您提供的值不在卸载的服务器上。它在加载的服务器上。

线程处理过程本身需要花费一些时间在服务器上,特别是当您有100或1000个请求时。在该级别,线程开销本身是有影响的,尤其是在加载时。 Async可以让你更好地将请求的工作分配给其他设施,以解决繁重的问题。请求线程然后简单地成为接待台,&#34;我如何指导您的呼叫&#34;运营商。一旦他们完成了工作路线,他们就可以继续接受其他请求。

理想情况下,您可能会注意到很多公司没有很多公司,我可以如何指导您的电话&#34;操作员,因为工作不是特别耗时。与实际执行请求的人相比,单个运营商可以指导大量呼叫。因此,与进行实际处理相比,仅需要更少的线程来接受请求和路由它们。

通过异步,您可以将应用程序内部转移到其中一个客户支持位置,这些位置可以让您的人与人之间保持一致。这实际上可以让你的系统在负载下表现得更有效率,因为人们并没有全部卡在走廊里,而是安静地坐在个人等候室(队列)等待轮到他们真正的工作。

这是Java Servlets中Async工具的价值。通过一个简单的微基准测试来做你正在做的事情,他们无缘无故地做更多的工作。