最近我问了问题Spring WebFlux create pool of no-blocking threads
我得到了答案,阅读了所提供的链接,但仍然不理解做这些事情的正确方法。
我使用 Spring WebFlux(WebClient)来编写我的REST服务。对于每个传入的请求,我向另一个REST服务发出了数百个请求,因此为了尽可能快地使它们,我想使用无阻塞线程。
让我收到客户的请求,我必须拨打600个API:
List<String> urls = Arrays.asList("www.example-rest.com/url1", "www.example-rest.com/url2", ..., "www.example-rest.com/url600");
以下是计划程序的文档 http://projectreactor.io/docs/core/release/reference/#schedulers
我找到了有关弹性线程池的信息:
弹性线程池(Schedulers.elastic())。它创造了新的工人 根据需要使用池,并重用空闲池。这是I / O的不错选择 例如阻止工作。 Schedulers.elastic()是一种方便的方法 给一个阻塞进程自己的线程,这样它就不会占用 其他资源。
但是我无法为每个请求创建新的工作池,并且该池中的线程仍然以阻塞方式工作。
如果有人与 Spring WebClient 做了类似的任务,请提供一个示例,解释一下正确的方法。
答案 0 :(得分:0)
我做过类似的事情......我的目标是创建一个带有这样签名的方法:
Flux<BasicIssue> getIssues(WebClient webClient);
因为我调用的网站只提供了分页界面,所以我需要将多个REST调用的结果提供给一个Flux。以下是我的实施。请注意我使用CachedThreadPool。
Flux<BasicIssue> getIssues(WebClient webClient) {
return Flux.generate(
() -> new IssuesState(webClient),
(state, sink) -> {
BasicIssue ret = state.getNext();
if (ret == null) {
sink.complete();
} else {
sink.next(ret);
}
return state;
}
}
class IssuesState {
private final AtomicBoolean isDone = new AtomicBoolean(false);
private final AtomicInteger threadCount = new AtomicInteger(1);
private final Executor executor = Executors.newCachedThreadPool();
private final LinkedBlockingQueue<BasicIssue> issueQueue = new LinkedBlockingQueue();
public IssuesState(WebClient webClient) {
executor.execute(() -> getNextBlock(webClient, 0));
}
private void getNextBlock(final WebClient webClient, final int startAt) {
webClient
.get()
.uri(...)
.header("Authorization", "Basic " + Base64Utils.encodeToString(("username:password".getBytes(UTF_8))))
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(PageableIssue.class)
.subscribe(pageableIssue -> {
int maxResults = pageableIssue.getMaxResults();
int total = pageableIssue.getTotal();
if (startAt == 0) {
for (int i = startAt + maxResults; i < total; i += maxResults) {
threadCount.incrementAndGet();
final int x = i;
executor.execute(() -> getNextBlock(webClient, x));
}
}
synchronized (issueQueue) {
for (BasicIssue issue : pageableIssue.getIssues()) {
issueQueue.add(issue);
}
if (threadCount.decrementAndGet() == 0) {
isDone.set(true);
}
}
});
}
public BasicIssue getNext() {
synchronized (issueQueue) {
if (isDone.get() && issueQueue.isEmpty()) {
return null;
}
}
try {
return issueQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
使用上述方法..
getIssues(webClient)
.subscribe(basicIssue -> System.out.println(basicIssue.getName());