我在测试中经常使用
Awaitility
来处理异步操作。但是,每个 Awaitility
调用都会生成线程,这会导致运行大型测试时内存消耗较高。我正在寻找一种替代解决方案,它提供类似的功能,但内存效率更高。
下面是一个简化的示例,我需要在
0
和 10,000,000
之间找到 500 个随机素数。
使用等待:
static void waitWithAwaitility() {
AtomicInteger primeCount = new AtomicInteger(0);
await()
.atMost(1, TimeUnit.HOURS)
.pollInterval(3, TimeUnit.SECONDS)
.until(() -> {
int number = supplierMethod().get();
if (isPrime(number)) {
System.out.println("Found prime: " + number);
primeCount.incrementAndGet();
}
return primeCount.get() >= 500;
});
}
辅助方法:
public static Supplier<Integer> supplierMethod() {
int number = new Random().nextInt(10_000_000) + 1;
System.out.println("Generated number: " + number);
return () -> number;
}
public static boolean isPrime(int number) {
if (number <= 1) return false;
for (int i = 2; i <= Math.sqrt(number); i++) {
if (number % i == 0) return false;
}
return true;
}
当我使用 VisualVM 等工具分析内存使用情况时,我注意到内存占用量很大。
ChatGPT 建议使用反应式编程(使用 Project Reactor)作为替代方案。我尝试实施以下解决方案:
反应式编程示例:
public Mono<Integer> reactiveAwait(
Supplier<Integer> supplierMethod,
Predicate<Integer> condition,
Duration pollInterval,
Duration timeout
) {
return Mono.defer(() -> Mono.fromSupplier(supplierMethod))
.repeatWhen(repeat -> repeat.delayElements(pollInterval))
.takeUntil(condition::test)
.last()
.timeout(timeout, Mono.error(new RuntimeException("Timeout exceeded")))
.onErrorResume(throwable -> {
System.err.println(throwable.getMessage());
return Mono.empty();
})
.subscribeOn(Schedulers.boundedElastic());
}
static void waitWithJavaRx() {
AtomicInteger primeCount = new AtomicInteger(0);
Mono<Integer> result = new DifferentAwaitility().reactiveAwait(
() -> supplierMethod().get(),
number -> {
boolean primeStatus = isPrime(number);
System.out.println("Is prime? " + primeStatus);
if (primeStatus) {
primeCount.incrementAndGet();
}
return primeCount.get() >= 500;
},
Duration.ofSeconds(3),
Duration.ofHours(1)
);
Integer finalResult = result.block();
if (finalResult != null) {
System.out.println("Result: " + finalResult);
} else {
System.err.println("Error: Timeout or other failure occurred");
}
}
反应式方法的问题:
虽然这种方法有效,但内存消耗比使用
Awaitility
时高出三倍。以下是比较内存使用情况的 VisualVM 屏幕截图:
问题:
是否有更好的方法来实现与
Awaitility
类似的功能,但内存消耗更低?我探索过响应式编程,但它对减少内存使用没有帮助。任何建议或优化将不胜感激!
您是否尝试过按照 Awaitlity 文档中所述使用 ExecutorService?
https://github.com/awaitility/awaitility/wiki/Usage#thread-handling
至于反应式和更高的内存占用,我的猜测是它可能运行得更快,从而更快地分配对象,但这只是一个大脑放屁。