现在我负责一个服务,主要是融合功能,根据传过来的参数,来调用上游的 A 、B 、C 三个 dubbo 服务,三个服务相互没有依赖,超时就丢弃,无所谓,然后拿到数据把他们 merge 一下,返回给下游。
这个时候,A B C 三个服务 dubbo 超时设置的都是 200ms,我想异步调用他们,就使用 CompletableFuture,然后自定线程池处理的。但有人说高 IO 不要用 CompletableFuture,那怎么做这个异步呢?
求解
1
127000 2020-03-31 12:47:51 +08:00
|
3
Foredoomed 2020-03-31 13:24:41 +08:00
自己定义个线程池, 然后用 CompletableFuture.runAsync(Runnable, Executor)
|
4
RRRSSS OP @Foredoomed 现在就是这么做的,关键是线程池定义多大,异步我了解得不多,我看网上说的是 CompletableFuture 适合 CPU 密集型任务,但是我这个是 高 IO 任务。
|
5
ayavvv 2020-03-31 14:20:47 +08:00
为什么 CompletableFuture 适合 CPU 密集型任务不适合高 IO 任务?
直接用 Future 行不行? |
6
Jafee 2020-03-31 14:21:13 +08:00
不如先找找 CompletableFuture 不适合 I/O 操作的原因再排除 CompletableFuture 。(个人能力有限,没想到是什么原因导致的这个规则)
“如果你并行的工作单元还涉及等待 I/O 的操作(包括网络连接等待),那么使用 CompletableFuture 灵活性更好。(与并行流相比较)” —— 《 Java 8 实战》 |
7
Foredoomed 2020-03-31 14:40:26 +08:00
线程池设个最大线程数就行了,不用太精确。你只要做压力测试就行了,网上又不是都对的。
|
8
optional 2020-03-31 14:45:37 +08:00
同步 call 都挺蛋疼,只能用线程池,可能线程池可以开大一点。
|
9
yqsas 2020-03-31 14:47:05 +08:00 via iPhone
|
10
Aresxue 2020-03-31 14:50:15 +08:00
CompletableFuture 是最佳方案,dubbo 自己的异步调用就支持。话说 IO 多才更适合使用 CompletableFuture, 能让 CPU 更充分利用,谁说不利于高 IO 的?我能想到的只是高 IO 对系统危害比较大, 以及失败及异常处理较为复杂。
|
11
NeinChn 2020-03-31 14:55:06 +08:00
记错了吧,绝大部分情况下请不要开多线程跑 CPU 密集型任务
除非是单机就你一个请求在跑的场景,比如客户端,单机训练 IO 操作只要是可以并行的,建议都并行跑. |
12
wysnylc 2020-03-31 14:58:21 +08:00
@Jafee #6 计算密集型时设定线程池为虚拟核心数即可,IO 密集型则根据实际任务决定
CompletableFuture 和 parallelStream 一样默认使用 ForkJoinPool 的线程池,ForkJoinPool 默认线程数是虚拟核心数 所以 CompletableFuture 默认适合计算密集型,需要 IO 密集型则要自己定义线程池 说 CompletableFuture 不适应 IO 密集型的要么是个半吊子,要么故意说一半藏一半误导别人,非蠢即坏 |
13
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 的方式在处理任务,高延迟的任务会影响整理进度吧? 疯狂猜测 |
14
LeeSeoung 2020-03-31 15:05:30 +08:00
CompletableFuture 、CompositeFuture 。。= =我一度以为我记错了,原来这两个不一样的。。偏题了
|
15
xiaoidea 2020-03-31 17:28:58 +08:00
我就是开线程池的
|
16
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) |
17
gaius 2020-03-31 21:40:19 +08:00 via Android
可以指定自定义的线程池
|
18
renyijiu 2020-03-31 21:46:43 +08:00
制定一个线程池就好了,常用的 io 型数量可以 cpu * 2 + 1
|
19
1424659514 2020-04-01 08:43:42 +08:00
CompletableFuture 指定一个线程池就可以了, 用这个方法
runAsync(Runnable runnable,Executor executor) |
20
sagaxu 2020-04-01 10:28:33 +08:00 via Android
CompletableFuture 用 ForkJoinPool 线程数少不擅长 IO 密集型?正好相反,所有擅长 IO 密集型的解决方案,核心思想之一就是减少线程数。
|