java - 使用多线程或优先队列确定特定 API 调用优先级的方法?

标签 java multithreading parallel-processing jersey priority-queue

在我的应用程序中,我的 servlet(在 tomcat 上运行)接受一个 doPost 请求,它返回一个 api 调用的初始值给用户进行展示,然后在后面做大量的数据分析,还有更多其他 api 调用。数据分析然后进入我的mongodb。当我想在批量 api 调用完成之前启动该过程时,就会出现问题。电话太多,我至少需要 20 秒。我不希望用户等待 20 秒来显示他们的初始数据,所以我希望暂停数据分析,让新请求调用该初始 api 进行显示。

这是我的函数在 doPost 之后的一般结构(异步所以这是在 Runnable 中)。它有点长,所以我将其缩写以便于阅读:

private void postMatches(ServletRequest req, ServletResponse res) {
        ... getting the necessary fields from the req ...
        /* read in values for arrays */
        String rankQueue = generateQueryStringArray("RankedQueues=", "rankedQueues", info);
        String season = generateQueryStringArray("seasons=", "seasons", info);
        String champion = generateQueryStringArray("championIds=", "championIds", info);
        /* first api call, "return" this and then start analysis */
        JSONObject recentMatches = caller.callRiotMatchHistory(region, "" + playerId);
        try {
            PrintWriter out = res.getWriter();
            out.write((new Gson()).toJson(recentMatches));
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        /* use array values to send more api calls */
        JSONObject matchList = caller.callRiotMatchList(playerId, region, rankQueue, season, champion);
        ... do a ton more api calls with the matchList's id's...
    }

所以我的一个想法是

每个客户端有两个线程。

这样一来,就会有一个线程调用单个 api 调用,而另一个线程将调用其余的 999 个 api 调用。这样,单个 api 调用线程将只等到来自同一客户端的另一个 doPost 出现并立即调用 api,并且随之而来的批量 api 调用将被附加到另一个线程。通过这样做,两个线程将并行计算。

有一个优先级队列,将初始调用置于高优先级

这样,每个 URL 都将通过队列传递,我可以选择特定 URL 的 compareTo 更大(可能将其包装在一个 bean 中)。但是,我不确定 api 调用者如何能够区分哪个调用是哪个,因为一旦将 url 添加到队列中,它就会失去身份。有什么办法可以解决这个问题吗?我知道回调在 Java 中不可用,所以很难做到这一点。

这两种想法中的任何一种都可能吗?无需代码,但将不胜感激!

PS:我正在使用 Jersey 进行 API 调用。

最佳答案

对您来说最好的选择似乎是使用“每个客户端两个线程”的解决方案。或者更确切地说是它的变体。

我认为您正在调用的 API 将有一些速率限制,因此大量调用将被自动阻止。这对您来说是有问题的,因为您同时处理的几个请求可能很容易达到这个限制。

此外,您可能会迟早达到 I/O 限制,具体取决于您的计算时间密集程度。这意味着您应该对后台 API 调用有一个内在限制,初始请求应该没有任何内在限制。因此 fixed-size ThreadPool似乎是完美的解决方案。将其公开为静态 ExecutorService在您的服务中应该是最简单的解决方案。

因此,我建议您公开一个静态服务,该服务将 matchList 作为参数,然后“照办”。

它可能看起来像这样:

public class MatchProcessor {
    private static final ExecutorService service = Executors.newFixedThreadPool(THREADS);

    public static void processMatchList(final JSONObject matchList) {
        service.submit(() -> runAnalysis(matchList));
    }

    private static void runAnalysis(final JSONObject matchList) {
       //processing goes here
    }
}

旁注:此代码使用 java 8,如果您使用的是 Java 7,将提交的 lambda 转换为 Runnable 应该很简单

关于java - 使用多线程或优先队列确定特定 API 调用优先级的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32198561/

相关文章:

java - 创建纹理图集错误(opengl ES 2.0,android)

java - 为什么 javax.ws.rs.core.UriBuilder、fromUri() 方法在主机名 URI 末尾添加额外的 "/"?

C++ 线程/vector 聊天

python - 如何将 python Socket.IO 与 Qt 集成

javascript - JavaScript/NodeJS 真的是并行的吗?

performance - 最佳进程数?

java - DefaultListModel 是否会覆盖我的 Action 监听器中的 Action 顺序?

Java:通配符边界的非运算符

c# - 异步方法应该有什么行为?

parallel-processing - Gradle : Run subproject's tasks in parallel