目前,我正在使用其内置的REST API从服务中提取大量数据。目前,该服务返回JSON格式的文件大约需要600毫秒,而我需要返回495个JSON格式的文件。
作为我的原始POC,我只是在主线程中线性调用了它们(在所有查询完成之前,都不希望程序前进),这大约需要300秒才能完成。既然我已经展示了POC,我需要对它进行一些优化,因为5分钟的查询不是很理想。目前,我正在使用具有固定线程池的Executor服务,并向该服务添加495个任务,然后调用All()。
我唯一的问题是,现在我得到的数据值不好。从逻辑上讲,什么都没有改变,查询一次只返回50个元素,所以我所做的就是更改起点(我已经检查了起点,URL中没有重叠)。由于某些原因,我缺少了结果,并且有重复的现有结果。处理JSON的代码没有改变,唯一改变的是获得结果的方法。
我最初以为我的遍历变量有一个问题,它不是Atomic,但是在获取JSON之后真正发生的一切就是解析它,创建一个Requirement对象,然后将其添加到Set中。 。由于从未重新定义过Set,所以给人的印象是原子不会有任何改变(但是我可能100%错误)。
下面的代码片段是我如何在主线程上线性运行ti,而下面的代码片段是我的版本,其中包括多线程。我确实知道这有点混乱,这是我目前的POC,用于确定多线程的速度(当前从〜300秒变为〜45秒),以及是否值得将其应用于程序中的其他调用。
我只需要弄清楚为什么在使用多个线程时会重复和丢失值(线性调用时没有重复或丢失值)。 URL决定了起点,大小始终不变,我无法弄清楚为什么我要2000个简短的需求和224个重复的条目,而根本不应该包含任何内容。
唯一更改的是Executor Service和我获得startingPoint的循环(也就是我只是计算需要多少循环,而不是依赖于返回的当前位置)。 creatRequirement(obj)函数所做的全部工作就是进一步解析JSON文件,并使用从JSON传递到构造函数中的数据来创建Requirement Object。
private void obtainAllRequirements() {
int startingLocation = 0;
boolean continueQueries = true;
String output = null;
do {
output = executeRESTCall(baseUrl + "/abstractitems?maxResults=50&itemType=43&startAt=" + startingLocation);
JSONObject obj = new JSONObject(output);
if ((obj.getJSONObject("meta").getJSONObject("pageInfo").getInt("totalResults") - startingLocation) <= 50) {
continueQueries = false;
}
createRequirements(obj);
startingLocation += 50;
} while (continueQueries);
}
private void obtainAllRequirements() {
String output = executeRESTCall(baseUrl + "/abstractitems?itemType=43&startAt=0");
int totalResults = new JSONObject(output).getJSONObject("meta").getJSONObject("pageInfo").getInt("totalResults");
ExecutorService service = Executors.newFixedThreadPool(THREADS);
List<Callable<Void>> tasks = new ArrayList<>();
for (int i = 0; i < Math.ceil(totalResults/MAX_RESULTS); i++){
final int iteration = i;
tasks.add(new Callable<Void>() {
@Override
public Void call() throws Exception {
System.out.println(baseUrl + "/abstractitems?maxResults="+MAX_RESULTS+"&itemType=43&startAt=" + (iteration*MAX_RESULTS));
String o = executeRESTCall(baseUrl + "/abstractitems?maxResults="+MAX_RESULTS+"&itemType=43&startAt=" + (iteration*MAX_RESULTS));
JSONObject obj = new JSONObject(o);
createRequirements(obj);
return null;
}
});
}
try {
service.invokeAll(tasks);
service.shutdown();
}catch (InterruptedException e){
e.printStackTrace();
}
}
编辑:这是在创建需求内部发生的情况,需求的构造函数仅获取JSON数据并将值分配给特定的私有变量成员。
private void createRequirements(JSONObject json) {
JSONArray dataArray = json.getJSONArray("data"); // Gets the data array in the JSON file
for (int i = 0; i < dataArray.length(); i++) {
JSONObject req = dataArray.getJSONObject(i);
Requirement requirement = new Requirement(req);
if (!requirement.INVALID_PROJECT) {
requirements.add(requirement);
}
}
}
编辑:将需求的设置添加为ConcurrentSet,但没有更改。
this.requirements = new ConcurrentHashMap<>().newKeySet();
编辑:添加了执行的REST调用
public String executeRESTCall(String urlValue) {
try {
URL url = new URL(urlValue);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
String encoding = Base64.getEncoder()
.encodeToString((Credentials.XXX + ":" + Credentials.XXX).getBytes("UTF-8"));
conn.setRequestProperty("Authorization", "Basic " + encoding);
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
return br.readLine();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
答案 0 :(得分:1)
不要忘记例外情况
您可能还需要等待任务实际完成。
您将需要更好的异常处理,但现在请对此进行测试(使用多个线程)并发布输出:
round
答案 1 :(得分:-1)
我所做的只是将固定线程的数量从400减少到了10。不知道为什么选择400,我不认为JVM可以处理线程,而且我不会不必担心。将其降到10可以解决我丢失和重复数据的问题,我不知道为什么会这样,我很想知道为什么。