rxjava 循环发送事件
Spring Framework 4.2 GA即将发布,让我们看一下它提供的一些新功能。 引起我注意的一个事件是一个简单的新类SseEmitter
,它是对Spring MVC控制器中容易使用的发送事件的抽象。 SSE是一项技术,可让您在一个HTTP连接内沿一个方向将数据从服务器流式传输到浏览器。 听起来像是websocket可以做什么的子集。 但是,由于它是一个简单得多的协议,因此可以在不需要全双工的情况下使用,例如实时推动股价变化或显示长时间运行的进程。 这将是我们的例子。
假设我们有一个具有以下API的虚拟硬币矿工:
public interface CoinMiner {
BigDecimal mine() {
//...
}
}
每次调用mine()
我们都必须等待几秒钟,才能获得大约1个硬币的回报(平均)。 如果要挖掘多个硬币,则必须多次调用此方法:
@RestController
public class MiningController {
//...
@RequestMapping("/mine/{count}")
void mine(@PathVariable int count) {
IntStream
.range(0, count)
.forEach(x -> coinMiner.mine());
}
}
这项工作,我们可以请求/mine/10
和mine()
方法将执行10次。 到目前为止,一切都很好。 但是挖掘是一项占用大量CPU的任务,将计算分散到多个内核将是有益的。 此外,即使使用并行化,我们的API端点也相当慢,我们必须耐心等待直到所有工作完成而没有任何进度通知。 让我们首先修复并行性–但是,由于并行流无法控制底层线程池,因此我们来使用显式的ExecutorService
:
@Component
class CoinMiner {
CompletableFuture<BigDecimal> mineAsync(ExecutorService executorService) {
return CompletableFuture.supplyAsync(this::mine, executorService);
}
//...
}
客户端代码必须显式提供ExecutorService
(只是设计选择):
@RequestMapping("/mine/{count}")
void mine(@PathVariable int count) {
final List<CompletableFuture<BigDecimal>> futures = IntStream
.range(0, count)
.mapToObj(x -> coinMiner.mineAsync(executorService))
.collect(toList());
futures.forEach(CompletableFuture::join);
}
首先多次调用mineAsync