Java 异步问题

2020-03-31 12:35:18 +08:00
 RRRSSS

现在我负责一个服务,主要是融合功能,根据传过来的参数,来调用上游的 A 、B 、C 三个 dubbo 服务,三个服务相互没有依赖,超时就丢弃,无所谓,然后拿到数据把他们 merge 一下,返回给下游。

这个时候,A B C 三个服务 dubbo 超时设置的都是 200ms,我想异步调用他们,就使用 CompletableFuture,然后自定线程池处理的。但有人说高 IO 不要用 CompletableFuture,那怎么做这个异步呢?

求解

3665 次点击
所在节点    程序员
20 条回复
127000
2020-03-31 12:47:51 +08:00
RRRSSS
2020-03-31 12:50:10 +08:00
@127000 这个我看到了,不过需要 3 个上游都改接口,沟通成本太大,所以想着自己这边做。
Foredoomed
2020-03-31 13:24:41 +08:00
自己定义个线程池, 然后用 CompletableFuture.runAsync(Runnable, Executor)
RRRSSS
2020-03-31 14:13:21 +08:00
@Foredoomed 现在就是这么做的,关键是线程池定义多大,异步我了解得不多,我看网上说的是 CompletableFuture 适合 CPU 密集型任务,但是我这个是 高 IO 任务。
ayavvv
2020-03-31 14:20:47 +08:00
为什么 CompletableFuture 适合 CPU 密集型任务不适合高 IO 任务?
直接用 Future 行不行?
Jafee
2020-03-31 14:21:13 +08:00
不如先找找 CompletableFuture 不适合 I/O 操作的原因再排除 CompletableFuture 。(个人能力有限,没想到是什么原因导致的这个规则)

“如果你并行的工作单元还涉及等待 I/O 的操作(包括网络连接等待),那么使用 CompletableFuture 灵活性更好。(与并行流相比较)” —— 《 Java 8 实战》
Foredoomed
2020-03-31 14:40:26 +08:00
线程池设个最大线程数就行了,不用太精确。你只要做压力测试就行了,网上又不是都对的。
optional
2020-03-31 14:45:37 +08:00
同步 call 都挺蛋疼,只能用线程池,可能线程池可以开大一点。
yqsas
2020-03-31 14:47:05 +08:00
Aresxue
2020-03-31 14:50:15 +08:00
CompletableFuture 是最佳方案,dubbo 自己的异步调用就支持。话说 IO 多才更适合使用 CompletableFuture, 能让 CPU 更充分利用,谁说不利于高 IO 的?我能想到的只是高 IO 对系统危害比较大, 以及失败及异常处理较为复杂。
NeinChn
2020-03-31 14:55:06 +08:00
记错了吧,绝大部分情况下请不要开多线程跑 CPU 密集型任务
除非是单机就你一个请求在跑的场景,比如客户端,单机训练
IO 操作只要是可以并行的,建议都并行跑.
wysnylc
2020-03-31 14:58:21 +08:00
@Jafee #6 计算密集型时设定线程池为虚拟核心数即可,IO 密集型则根据实际任务决定
CompletableFuture 和 parallelStream 一样默认使用 ForkJoinPool 的线程池,ForkJoinPool 默认线程数是虚拟核心数
所以 CompletableFuture 默认适合计算密集型,需要 IO 密集型则要自己定义线程池
说 CompletableFuture 不适应 IO 密集型的要么是个半吊子,要么故意说一半藏一半误导别人,非蠢即坏
nickchenyx
2020-03-31 14:59:32 +08:00
基本上还是一个 CompletableFuture + 自定义线程池解决这种问题的,不过这也有缺陷。

Q:A 、B 、C 三个接口耗时不同,例如 C 不稳定,rt 比 A 、B 高很多,这时候就会因为 C 的 rt 影响整体的吞吐
A: 线程池隔离,使用独立的线程池资源,隔离 C 的访问调用
Q:C 的访问隔离了之后,如何处理 C 访问过慢的问题呢
A:抛弃策略处理,或者使用 熔断 + FallbackFactory 构造默认返回

说到这里基本就是 hystrix 做的事情了,各种熔断时间配置,资源隔离的颗粒度,这都是可以看 hystrix 的文档可以看到的。

(有人说高 IO 不要用 CompletableFuture 这个问题,我觉得可能是因为底层还是使用 ForkJoin 的方式在处理任务,高延迟的任务会影响整理进度吧? 疯狂猜测
LeeSeoung
2020-03-31 15:05:30 +08:00
CompletableFuture 、CompositeFuture 。。= =我一度以为我记错了,原来这两个不一样的。。偏题了
xiaoidea
2020-03-31 17:28:58 +08:00
我就是开线程池的
bringyou
2020-03-31 17:44:28 +08:00
估计是因为 CompletableFuture 的 runAsync 等不带线程池入参的方法,使用的是默认的 forkJoinPool,这个线程池的线程数量是固定的 cpu 数目,且是整个 JVM 共享的,不太适合跑高 IO 应用。
建议使用带线程池入参的方法,传进去自定义线程池。这个自定义线程池的最大线程数可以设置高一点。举个例子,[kotlin 里面跑 IO 协程的调度器,设置的最少 64 个线程]( https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/jvm/src/scheduling/Dispatcher.kt#L17)
gaius
2020-03-31 21:40:19 +08:00
可以指定自定义的线程池
renyijiu
2020-03-31 21:46:43 +08:00
制定一个线程池就好了,常用的 io 型数量可以 cpu * 2 + 1
1424659514
2020-04-01 08:43:42 +08:00
CompletableFuture 指定一个线程池就可以了, 用这个方法

runAsync(Runnable runnable,Executor executor)
sagaxu
2020-04-01 10:28:33 +08:00
CompletableFuture 用 ForkJoinPool 线程数少不擅长 IO 密集型?正好相反,所有擅长 IO 密集型的解决方案,核心思想之一就是减少线程数。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.fyfyfm.apispeedy.workers.dev/t/657894

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX