在我的应用程序中,我的 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/