CompletableFuture 在 complete 上缓慢工作
CompletableFuture working slowly on complete
所以我已经 运行对 CompletableFuture class 进行了一些测试,并且我偶然发现了一些我无法解释的奇怪行为。
问题
我已经设法将问题减少到这个代码片段
long nanos = System.nanoTime();
CompletableFuture<UUID> someFuture = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
return UUID.randomUUID();
});
someFuture.get(5, TimeUnit.SECONDS);
System.out.println((System.nanoTime() - nanos) / 1_000_000 + "ms");
我希望这段代码在大约 10 毫秒内达到 运行。出于某种原因,运行ning 它最终花费了大约 500 毫秒!应该注意的是,这只发生在第一次执行代码时,后续执行似乎需要大约 10-15 毫秒(这是我所期望的)。
我的问题是,我可以做些什么来摆脱它,要么通过优化它,要么不使用 CompletableFuture。
我试过的
- 我试过使用 Runnable 而不是 lambda,没有效果。
- 我尝试覆盖 CompletableFuture 的
get(long timeout, TimeUnit unit)
以每毫秒轮询一次结果。这将延迟差异从 12 毫秒减少到大约 2-3 毫秒,但是,它不会影响冷启动时间。
- 我已经尝试启动新线程来完成未来,调用
ForkJoinPool.commonPool()
,尝试使用 Executors.newCachedThreadPool()
和 Executors.newFixedThreadPool(2);
。据我所知没有影响。
背景
我的场景(为了避免 XY 问题)是我试图通过 TCP 制作一个简单的请求-回复模型。我用 UUID 标记每个请求并将其保存在 ConcurrentHashMap<UUID, CompletableFuture<String>>
中,当数据包返回时,我从地图中获取可完成的未来并通过回复完成它。我这样做是因为预计不会按顺序回复。我遇到了 100 毫秒的延迟(虽然一直如此,不仅仅是第一次执行),即使服务器和客户端都在本地主机上 运行ning。我已经仔细检查过这个问题不是网络方面的问题,据我所知,瓶颈归结为 CompletableFuture 很慢。这样的 Map
是解决这个问题的好方法吗?如果是这样,我怎样才能消除延迟,如果不是,我将如何设计这样的东西?
来自the docs of UUID.randomUUID
:
Static factory to retrieve a type 4 (pseudo randomly generated) UUID. The UUID is generated using a cryptographically strong pseudo random number generator.
加密 RNG 的缺点是速度慢。因为是伪随机数生成器,生成好随机数慢的问题只有在创建随机数生成器时才存在。
如果你看一下 the OpenJDK sources of UUID.randomUUID
,你会发现第一个随机数生成器是使用一个简单但有效的单例获得的,只要它被首次调用(当 class Holder
已加载):
private static class Holder {
static final SecureRandom numberGenerator = new SecureRandom();
}
SecureRandom ng = Holder.numberGenerator;
作为解决方案,您可以 运行 UUID.randomUUID()
在程序启动时在后台更早地完成工作。
如果您不需要加密强度高的 UUID,您可以使用非加密强度高的 RNG 创建它们:
Random rand=new Random();//do this once
//do this whenever you need a new UUID
UUID uuid=new UUID(rand.nextLong(),rand.nextLong());
所以我已经 运行对 CompletableFuture class 进行了一些测试,并且我偶然发现了一些我无法解释的奇怪行为。
问题
我已经设法将问题减少到这个代码片段
long nanos = System.nanoTime();
CompletableFuture<UUID> someFuture = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
return UUID.randomUUID();
});
someFuture.get(5, TimeUnit.SECONDS);
System.out.println((System.nanoTime() - nanos) / 1_000_000 + "ms");
我希望这段代码在大约 10 毫秒内达到 运行。出于某种原因,运行ning 它最终花费了大约 500 毫秒!应该注意的是,这只发生在第一次执行代码时,后续执行似乎需要大约 10-15 毫秒(这是我所期望的)。
我的问题是,我可以做些什么来摆脱它,要么通过优化它,要么不使用 CompletableFuture。
我试过的
- 我试过使用 Runnable 而不是 lambda,没有效果。
- 我尝试覆盖 CompletableFuture 的
get(long timeout, TimeUnit unit)
以每毫秒轮询一次结果。这将延迟差异从 12 毫秒减少到大约 2-3 毫秒,但是,它不会影响冷启动时间。 - 我已经尝试启动新线程来完成未来,调用
ForkJoinPool.commonPool()
,尝试使用Executors.newCachedThreadPool()
和Executors.newFixedThreadPool(2);
。据我所知没有影响。
背景
我的场景(为了避免 XY 问题)是我试图通过 TCP 制作一个简单的请求-回复模型。我用 UUID 标记每个请求并将其保存在 ConcurrentHashMap<UUID, CompletableFuture<String>>
中,当数据包返回时,我从地图中获取可完成的未来并通过回复完成它。我这样做是因为预计不会按顺序回复。我遇到了 100 毫秒的延迟(虽然一直如此,不仅仅是第一次执行),即使服务器和客户端都在本地主机上 运行ning。我已经仔细检查过这个问题不是网络方面的问题,据我所知,瓶颈归结为 CompletableFuture 很慢。这样的 Map
是解决这个问题的好方法吗?如果是这样,我怎样才能消除延迟,如果不是,我将如何设计这样的东西?
来自the docs of UUID.randomUUID
:
Static factory to retrieve a type 4 (pseudo randomly generated) UUID. The UUID is generated using a cryptographically strong pseudo random number generator.
加密 RNG 的缺点是速度慢。因为是伪随机数生成器,生成好随机数慢的问题只有在创建随机数生成器时才存在。
如果你看一下 the OpenJDK sources of UUID.randomUUID
,你会发现第一个随机数生成器是使用一个简单但有效的单例获得的,只要它被首次调用(当 class Holder
已加载):
private static class Holder {
static final SecureRandom numberGenerator = new SecureRandom();
}
SecureRandom ng = Holder.numberGenerator;
作为解决方案,您可以 运行 UUID.randomUUID()
在程序启动时在后台更早地完成工作。
如果您不需要加密强度高的 UUID,您可以使用非加密强度高的 RNG 创建它们:
Random rand=new Random();//do this once
//do this whenever you need a new UUID
UUID uuid=new UUID(rand.nextLong(),rand.nextLong());