Java 异步问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
RRRSSS
V2EX    程序员

Java 异步问题

  •  1
     
  •   RRRSSS 2020-03-31 12:35:18 +08:00 4239 次点击
    这是一个创建于 2075 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    求解

    第 1 条附言    2020-03-31 20:44:48 +08:00
    看了大家的留言,自己再研究了一下,也问了公司同事,应该是这样的:

    CompletableFuture 默认使用线程池是 ForkJoinPool,而 ForkJoinPool 默认的线程数是 CPU 核数 - 1,擅长处理 CPU 密集型任务,而 IO 密集型任务需要自己合理配置的线程池(至于怎么设置,有经验问题,也可以压测慢慢调整,这个属于 JVM 调优部分)。
    20 条回复    2020-04-01 10:28:33 +08:00
    127000
        1
    127000  
       2020-03-31 12:47:51 +08:00
    RRRSSS
        2
    RRRSSS  
    OP
       2020-03-31 12:50:10 +08:00
    @127000 这个我看到了,不过需要 3 个上游都改接口,沟通成本太大,所以想着自己这边做。
    Foredoomed
        3
    Foredoomed  
       2020-03-31 13:24:41 +08:00
    自己定义个线程池, 然后用 CompletableFuture.runAsync(Runnable, Executor)
    RRRSSS
        4
    RRRSSS  
    OP
       2020-03-31 14:13:21 +08:00
    @Foredoomed 现在就是这么做的,关键是线程池定义多大,异步我了解得不多,我看网上说的是 CompletableFuture 适合 CPU 密集型任务,但是我这个是 高 IO 任务。
    ayavvv
        5
    ayavvv  
       2020-03-31 14:20:47 +08:00
    为什么 CompletableFuture 适合 CPU 密集型任务不适合高 IO 任务?
    直接用 Future 行不行?
    Jafee
        6
    Jafee  
       2020-03-31 14:21:13 +08:00
    不如先找找 CompletableFuture 不适合 I/O 操作的原因再排除 CompletableFuture 。(个人能力有限,没想到是什么原因导致的这个规则)

    “如果你并行的工作单元还涉及等待 I/O 的操作(包括网络连接等待),那么使用 CompletableFuture 灵活性更好。(与并行流相比较)” 《 Java 8 实战》
    Foredoomed
        7
    Foredoomed  
       2020-03-31 14:40:26 +08:00
    线程池设个最大线程数就行了,不用太精确。你只要做压力测试就行了,网上又不是都对的。
    optional
        8
    optional  
       2020-03-31 14:45:37 +08:00
    同步 call 都挺蛋疼,只能用线程池,可能线程池可以开大一点。
    yqsas
        9
    yqsas  
       2020-03-31 14:47:05 +08:00 via iPhone
    Aresxue
        10
    Aresxue  
       2020-03-31 14:50:15 +08:00
    CompletableFuture 是最佳方案,dubbo 自己的异步调用就支持。话说 IO 多才更适合使用 CompletableFuture, 能让 CPU 更充分利用,谁说不利于高 IO 的?我能想到的只是高 IO 对系统危害比较大, 以及失败及异常处理较为复杂。
    NeinChn
        11
    NeinChn  
       2020-03-31 14:55:06 +08:00
    记错了吧,绝大部分情况下请不要开多线程跑 CPU 密集型任务
    除非是单机就你一个请求在跑的场景,比如客户端,单机训练
    IO 操作只要是可以并行的,建议都并行跑.
    wysnylc
        12
    wysnylc  
       2020-03-31 14:58:21 +08:00
    @Jafee #6 计算密集型时设定线程池为虚拟核心数即可,IO 密集型则根据实际任务决定
    CompletableFuture 和 parallelStream 一样默认使用 ForkJoinPool 的线程池,ForkJoinPool 默认线程数是虚拟核心数
    所以 CompletableFuture 默认适合计算密集型,需要 IO 密集型则要自己定义线程池
    说 CompletableFuture 不适应 IO 密集型的要么是个半吊子,要么故意说一半藏一半误导别人,非蠢即坏
    nickchenyx
        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 的方式在处理任务,高延迟的任务会影响整理进度吧? 疯狂猜测
    LeeSeoung
        14
    LeeSeoung  
       2020-03-31 15:05:30 +08:00
    CompletableFuture 、CompositeFuture 。。= =我一度以为我记错了,原来这两个不一样的。。偏题了
    xiaoidea
        15
    xiaoidea  
       2020-03-31 17:28:58 +08:00
    我就是开线程池的
    bringyou
        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)
    gaius
        17
    gaius  
       2020-03-31 21:40:19 +08:00 via Android
    可以指定自定义的线程池
    renyijiu
        18
    renyijiu  
       2020-03-31 21:46:43 +08:00
    制定一个线程池就好了,常用的 io 型数量可以 cpu * 2 + 1
    1424659514
        19
    1424659514  
       2020-04-01 08:43:42 +08:00
    CompletableFuture 指定一个线程池就可以了, 用这个方法

    runAsync(Runnable runnable,Executor executor)
    sagaxu
        20
    sagaxu  
       2020-04-01 10:28:33 +08:00 via Android
    CompletableFuture 用 ForkJoinPool 线程数少不擅长 IO 密集型?正好相反,所有擅长 IO 密集型的解决方案,核心思想之一就是减少线程数。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2279 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 00:23 PVG 08:23 LAX 16:23 JFK 19:23
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86