我有大约40万个员工id,.I一次可以传递一个员工id。
如何使用线程并行调用PI,从而提高性能。需要一些指点。
saveInDatabase()方法将对象保存在数据库表中。
private void callApi(List<Long> employeeList, HttpEntity<String> requestEntity) {
Long employeeId;
for (Long i : employeeList) {
employeeId = i;// url
String url = "http://dummy.restapiexample.com/api/v1/employee/" + employeeId;
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity,
String.class);
saveInDatabase(responseEntity);
}
}
发布于 2019-07-21 21:33:23
直接使用Thread API很容易出错,因为它的级别较低。
使用parallelStream()
可能很有趣,但它也可能是一个问题,因为处理后的流可能会消耗应用程序可用的所有CPU核心。
这意味着您的应用程序的其他HTTP客户端请求可能最近才会得到处理。
允许指定池中可用线程数量的ExecutorService
API看起来是一个更好/更健壮的替代方案。
Spring Boot提供了一个包装它的built-in feature。
您可以将要调用的单个任务提取到方法中,如下所示:
@Async
public Future<ResponseEntity<String>> getEmployee(long employeeId, HttpEntity<String> requestEntity) {
String url = "http://dummy.restapiexample.com/api/v1/employee/" + employeeId;
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity,
String.class);
return new AsyncResult<ResponseEntity<String>>(responseEntity);
}
现在叫它:
private void callApi(List<Long> employeeList, HttpEntity<String> requestEntity) {
// Do async calls and store futures in a List
List<Future<ResponseEntity<String>>> futures = new ArrayList<>();
for (Long id : employeeList) {
futures.add(getEmployee(id, requestEntity));
}
// Then process list of future
for (Future<ResponseEntity<String>> future : futures)
try{
saveInDatabase(future.get());
}
catch(Exception e){
//handle the exception
}
}
}
顺便说一下,在循环中执行saveInDatabase()
操作不是一种正确的方法。
您希望批处理数据库插入,而不是批处理,因为您有许多数据库插入要做。类似于:
private void callApi(List<Long> employeeList, HttpEntity<String> requestEntity) {
List<ResponseEntity<String>> responseEntities =
employeeList.stream()
.map(id -> getEmploye(id))
.map(future -> {
try{return future.get();}
catch(Exception e){
//handle the exception
}
}
)
.collect(toList());
saveInDatabase(responseEntities);
}
要使@Asynch
功能正常工作,必须在应用程序的@Configuration
类上添加@EnableAsync
。
您还可以选择使用适合您需要的池/队列配置来定义Executor
bean。注意:如果您没有定义Spring,Executor
将创建一个SimpleAsyncTaskExecutor
并使用它(它通过任务创建一个Thread
,并且不重用它们)。
例如:
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
}
}
发布于 2019-07-21 21:16:36
您可以使用parallelStream()
并发调用API。
List<ResponseEntity<String>> result = employeeList.parallelStream()
.map(id->restTemplate.exchange("http://dummy.restapiexample.com/api/v1/employee/"+id, HttpMethod.GET, requestEntity, String.class))
.collect(Collectors.toList());
result.forEach(entity->saveInDatabase(entity));
但要注意,parallelStream()
可能会耗尽您的应用程序可用的CPU核心。如果应用程序不只执行此任务,而是设计为服务于其他请求,则可能会出现问题。
因此,按照@davidxxx建议,使用saveAll
进行批量插入
saveAll(result)
https://stackoverflow.com/questions/57133548
复制相似问题