【发布时间】:2019-01-21 12:26:50
【问题描述】:
在我开发的应用程序中,我需要执行大量的 REST 调用。我需要与之交互的 REST API 资源的架构是分层的,如下所示:
/api/continents - return list of all Earth's continents
/api/continents/{continent_name}/countries - return list of all countries on mentioned continent
/api/continents/{continent_name}/countries/{country_name}/cities - return list of all cities in mentioned country
不幸的是,这个 API 没有提供任何方法来获取所有城市,我需要首先获取所有大陆的列表,然后获取每个大陆的所有国家的列表,然后获取所有城市的列表每个大陆的每个国家。
首先,我尝试实现从该 API 获取所有城市的方法,而无需并行化,仅通过连续调用。类似的东西:
private List<City> getCities() {
List<Continent> continents = getAllContinents(); //HTTP GET call
List<Country> countries = new ArrayList<>();
for (Continent continent: continents) {
countries.addAll(getAllCountriesOfContinent(continent));
}
List<City> cities = new ArrayList<>();
for (Country country : countries) {
cities.addAll(getAllCitiesOfCountry(country));
}
return cities;
}
但这种方法运行速度太慢(具体执行时间约为 7 小时)。我决定尝试使用 Java Parallel Streams 和 CompletableFuture 来改进它,并得到了这样的方法:
private List<City> getCities() {
return getAllContinents()
.parallelStream()
.map(continent -> getAllCountriesOfContinent(continent))
.flatMap(feature -> feature.join().parallelStream())
.map(country -> getAllCitiesOfCountry(country))
.flatMap(feature -> feature.join().parallelStream())
.collect(Collectors.toList());
}
getAllCountriesOfContinent 和 getAllCitiesOfCountry 方法返回 CompletableFuture 列表的位置如下:
private CompletableFuture<List<Country>> getAllCountriesOfContinent(Continent continent) {
return CompletableFuture.supplyAsync(() -> {
return restClient.getDataFromApi(continent);
});
}
private CompletableFuture<List<City>> getAllCitiesOfCountry(Country country) {
return CompletableFuture.supplyAsync(() -> {
return restClient.getDataFromApi(country);
});
}
通过这样的重构,我得到了很好的性能提升(它执行了大约 25-30 分钟)。但我认为我可以使用 Java ThreadPoolExecutors 和 Threads 或 ForkJoin 框架对其进行更多改进。这些方法会帮助我提高代码的性能,还是有其他一些特殊的技术/算法/框架可以做到这一点?
【问题讨论】:
-
默认 CompletableFuture.supplyAsync 使用 fork join pool
-
几个问题,您使用的端点是否总是快速返回?您使用什么进行 HTTP get 调用?
-
@Welsh for HTTP 调用我使用的是 Apache HTTP 客户端,至于 API 的质量和速度 - 它非常一致和稳定。
-
@GlebKosteiko 只是确保您还确保您正在创建您的 HttpClient with multithreading 并且它不会在那里成为瓶颈。
-
感谢您的快速回归!
标签: java concurrency parallel-processing java-stream fork-join