我试图用Vert.x做一个非常简单的SSH客户端。由于我没有非阻塞的SSH库,我必须处理rxExecuteBlocking
中的所有内容。当我在一大块代码中运行所有逻辑时,它工作得很好,如下所示:
public Single<String> exec() {
return vertx.rxExecuteBlocking(f -> {
String result = "";
// connect()
// exec()
// close()
f.complete(result);
}, false);
}
// hostnames :: Observalbe<String>
hostnames()
.filter()
.flatMapSingle(this::exec)
.moreCalls()
.subscribe(); // OK
我宁愿让connect()
,exec()
,close()
分开并致电:
hostnames()
.filter()
.flatMapSingle(this::connect)
.moreCalls()
.flatMapSingle(this::exec)
.moreCalls()
.flatMapSingle(this::close)
.subscribe();
但是当运行多个阻止代码时
public Single<Connection> connect() {
return vertx.rxExecuteBlocking(f -> {
// connect
}, false);
}
public Single<Connection> exec() {
return vertx.rxExecuteBlocking(f -> {
// exec
}, false);
}
链在flatMapSingle(this::connect)
处停止,首先消耗filter()
的所有结果(建立所有连接),然后继续链接。此行为消耗了相当多的资源,因为所有连接都在内存中(此行为提醒我reduce()
或collect()
)
所需的结果将不会在链中停止并继续,释放资源并为每个事件执行此操作。
有没有办法做到这一点?
提前致谢。
答案 0 :(得分:0)
我建议尝试使用重载flatMap
,它将特定管道阶段的并发订阅的可观察量的最大数量作为参数。如果默认情况下工作线程池中有20个线程,则可以为每个flatMap
调用提供一小部分池,例如每个人5个。
hostnames()
// ...some filtering
.flatMap(hostname -> this.connect(hostname).toObservable(), 5)
// ...more operators
.flatMap(connection -> this.exec(connection).toObservable(), 5)
// ...more operators
.flatMap(connection -> this.close(connection).toObservable(), 5)
.subscribe();
这将确保不会在同一时刻使用整个线程池。
可能需要对并发加载进行一些调整。例如,如果connect
比exec
快,connect
的{{1}}和exec
的同时订阅的可观察量较少。因此,connect
之前的exec
的结果不会堆叠在缓冲区中。